Подтвердить что ты не робот

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 для ребенка никогда не запускался/что я могу сделать, чтобы он срабатывал?

4b9b3361

Ответ 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 звучит проще, но я хотел бы поместить это в альтернативу.