Rails вложенные атрибуты обратные вызовы детей не запускаются
Я сталкиваюсь с причудливой проблемой, когда дочерние обратные вызовы не запускаются при обновлении родителя...
У меня есть следующая настройка модели:
class Budget < ActiveRecord::Base
has_many :line_items
accepts_nested_attributes_for :line_items
end
class LineItem < ActiveRecord::Base
belongs_to :budget
before_save :update_totals
private
def update_totals
self.some_field = value
end
end
В моей форме у меня есть поля вложенные (построенные с помощью fields_for
):
= form_for @budget do |f|
= f.text_field :name
= f.fields_for :line_items do |ff|
= ff.text_field :amount
Почему обратный вызов update_totals
для ребенка никогда не запускался/что я могу сделать, чтобы он срабатывал?
Ответы
Ответ 1
У меня была такая же проблема. before_save
callback не вызывается, когда модель не изменяется.
Вы обновляете line_items
, а не budget
, поэтому рельсы считают, что он не обновляется и не вызывает save
для него.
Вам нужно изменить before_save
на after_validation
, чтобы он вызывается, даже если у модели нет измененных атрибутов. И когда в этом обратном вызове вы измените некоторые атрибуты, рельсы увидят, что ваша модель изменилась и вызовет save
.
Ответ 2
Старый вопрос, я знаю, но он все же появляется первым в поиске. Я думаю, что эта статья имеет решение:
Рельсы, вложенные атрибуты и обратные вызовы before_save
Если я правильно понимаю эту статью, проблема (как объясняет @AntonDieterle в своем ответе) заключается в том, что обратный вызов дочернего элемента не запускается, потому что родитель не "грязный". Это принципиальное решение состоит в том, чтобы "заставить" его быть грязным, вызывая attr_name_will_change!
в родительском атрибуте, который на самом деле не изменяется. См. [Active Model Dirty] в API Rails 2.
Антон-решение с использованием after_validation
вместо before_save
звучит проще, но я хотел бы поместить это в альтернативу.