2

Есть модели с has_many through имеет ассоциации:Как проверить наличие связанных записей в случае has_many через: association?

class Event < ActiveRecord::Base 
    has_many :event_categories 
    has_many :categories, through: :event_categories 

    validates :categories, presence: true 
end 

class EventCategory < ActiveRecord::Base 
    belongs_to :event 
    belongs_to :category 

    validates_presence_of :event, :category 
end 

class Category < ActiveRecord::Base 
    has_many :event_categories 
    has_many :events, through: :event_categories 
end 

вопрос с назначая event.categories = [] - он сразу же удаляет строку из event_categories. Таким образом, предыдущие ассоциации необратимо уничтожаются, и событие становится недействительным.

Как подтвердить наличие записей в случае has_many, through:?

UPD: внимательно прочитайте предложение, помеченное в полужирным шрифтом перед ответом. Rails 4.2.1

ответ

0

использование validates_associated, официальный documentaion является Here

+0

Из документов - «Проверяет, все ли соответствующие объекты или объекты действительны» и «Эта проверка не будет работать, если ассоциация не была назначена. Если вы хотите убедиться, что ассоциация присутствует и гарантирована, что она действительна, вам также необходимо использовать validates_presence_of. '. Но даже комбинация 'validates_presence_of: categories' и' validates_associated: categories' НЕ предотвращает немедленное удаление из таблицы 'event_categories' при назначении' event.category = [] ' – yurko

-1

Если вы используете RSpec в качестве основы тестирования, посмотрите на Shoulda Matcher. Вот пример:

describe Event do 
    it { should have_many(:categories).through(:event_categories) } 
end 
+0

Я не спрашиваю, как его протестировать, но как его проверить – yurko

1

вы должны создать пользовательскую проверку, например:

validate :has_categories 

def has_categories 
    unless categories.size > 0 
     errors.add(:base, "There are no categories" 
    end 
end 

Это показывает вам общее представление о том, что вы можете адаптировать это к вашим потребностям.

UPDATE

Этот пост пришел еще раз, и я нашел способ, чтобы заполнить пробелы.

Валидации могут оставаться такими, как указано выше. Все, что я должен добавить к этому, - это случай прямого назначения пустого набора категорий. Итак, как мне это сделать?

Идея проста: переопределите метод setter, чтобы не принимать пустой массив.

def categories=(value) 
    if value==[] 
     puts "Categories cannot be blank" 
    else 
     super(value) 
    end 
end 

Это будет работать для каждого задания, за исключением случаев, когда назначается пустой набор. Тогда просто ничего не произойдет. Ошибка не будет записана, и никакие действия не будут выполнены.

Если вы хотите добавить сообщение об ошибке, вам придется импровизировать. Добавьте атрибут к классу, который будет заполнен при звонке. Таким образом, чтобы сократить Короче говоря, эта модель работала для меня:

class Event < ActiveRecord::Base 
    has_many :event_categories 
    has_many :categories, through: :event_categories 

    attr_accessor :categories_validator # The bell 

    validates :categories, presence: true 
    validate :check_for_categories_validator # Has the bell rung? 

    def categories=(value) 
     if value==[] 
      self.categories_validator = true # Ring that bell!!! 
     else 
      super(value) # No bell, just do what you have to do 
     end 
    end 

private 
    def check_for_categories_validator 
     self.errors.add(:categories, "can't be blank") if self.categories_validator == true 
    end 
end 

Прибавив эту последнюю проверку, то экземпляр будет считаться недействительным, если вы:

event.categories = [] 

Хотя, никаких действий будет (обновление пропущено).

+0

это не мешает немедленному удалению из таблицы' event_categories' при назначении 'event.categories = []' – yurko

+0

Что делать, если вы попробуете 'event_categories .size' вместо ;? –

+0

такое же немедленное удаление из 'event_categories' – yurko