Вложенные модели и родительская проверка
У меня две модели.
- Parent
has_many Children
;
- Parent
accepts_nested_attributes_for Children
;
class Parent < ActiveRecord::Base
has_many :children, :dependent => :destroy
accepts_nested_attributes_for :children, :allow_destroy => true
validates :children, :presence => true
end
class Child < ActiveRecord::Base
belongs_to :parent
end
Я использую проверку для проверки наличия дочерних элементов для каждого родителя, поэтому я не могу сохранить родителя без детей.
parent = Parent.new :name => "Jose"
parent.save
#=> false
parent.children_attributes = [{:name => "Pedro"}, {:name => "Emmy"}]
parent.save
#=> true
работает валидация. Затем мы уничтожим детей с помощью атрибута _destroy
:
parent.children_attributes = {"0" => {:id => 0, :_destroy => true}}
parent.save
#=> true !!!
parent.reload.children
#=> []
поэтому я могу уничтожить всех детей через вложенные формы, и проверка будет проходить.
На самом деле это происходит, потому что после того, как я удалю дочерний элемент из моего родителя с помощью _delete
, метод children по-прежнему возвращает уничтоженный объект до его перезагрузки, поэтому проверка прошла:
parent.children_attributes = {"0" => {:id => 0, :_destroy => true}}
parent.save
#=> true !!!
parent.children
#=> #<Child id:1 ...> # It actually deleted
parent.reload.children
#=> []
Это ошибка?
В чем вопрос. Вопрос - лучшее решение для его ремонта. Мой подход заключается в том, чтобы добавить фильтр before_destroy к Child
, чтобы проверить, является ли он последним. Но это усложняет систему.
Ответы
Ответ 1
Это, вероятно, сработает для вас, но я чувствую, что там гораздо лучший ответ. Это звучит как ошибка для меня.
class Parent < ActiveRecord::Base
validate :must_have_children
def must_have_children
if children.empty? || children.all?(&:marked_for_destruction?)
errors.add(:base, 'Must have at least one child')
end
end
end
Ответ 2
Это не ошибка. Согласно документации
Подтверждает, что указанный атрибуты не являются пустыми (как определено по объекту # пусто?)
и validates :children, :presence => true
- это то же самое. В документации не говорится, что произойдет, если вы попытаетесь использовать ее в ассоциации. Вы должны использовать специальную проверку с помощью validate
.
Использование validates_presence_of
в has_many
ассоциации вызывает blank?
в ассоциации children
, которая является объектом класса Array. Поскольку blank?
не определен для Array
, он запускает method_missing
, который попадает в Rails. Обычно он делает то, что вы хотите, но я обнаружил, что он сбой в Rails 3.1rc и Ruby 1.8.7 действительно ужасно: он молча восстанавливает изменения связанных записей. Мне потребовалось пару часов, чтобы узнать, что происходит.