Вложенная форма Rails, вычисление значения из вложенных элементов во время

Я новичок в рельсах и работаю над одним из своих первых проектов на рельсах, это приложение для выставления счетов с вложенными элементами строки в форме счета. Я хочу рассчитать общий счет, прежде чем сохранить счет. Я получаю его для хорошего сохранения, если только что добавил элементы во время процесса сохранения, но он неправильно вычисляет общую сумму, если один из вложенных элементов строки помечен для удаления. Я должен был бы вернуться и сохранить снова, чтобы получить правильную общую сумму счета.

class Invoice < ActiveRecord::Base
  attr_accessible :job_name, :items_attributes, :tax1, :tax2, :subtotal

  before_save :calculate_totals


  has_many :items, :dependent => :destroy
  accepts_nested_attributes_for :items, allow_destroy: true

  private

  def calculate_totals
    self.subtotal = 0

    self.items.each do |i|
      self.subtotal = self.subtotal + (i.quantity * i.cost_per)
    end
  end
end

Я уверен, что это отличается от параметров, но запись элемента проблемы указана в запрошенных параметрах с :_destroy = true

{"utf8"=>"✓",
 "_method"=>"put",
 "authenticity_token"=>"+OqRa7vRa1CKPMCdBrjhvU6jzMH1zQ=",
 "invoice"=>{"client_id"=>"1",
 "job_name"=>"dsdsadsad",
 "items_attributes"=>{"0"=>{"name"=>"jhksadhshdkjhkjdh",
 "quantity"=>"1",
 "cost_per"=>"50.0",
 "id"=>"21",
 "_destroy"=>"false"},
 "1"=>{"name"=>"delete this one",
 "quantity"=>"1",
 "cost_per"=>"10.0",
 "id"=>"24",
 "_destroy"=>"true"}}},
 "commit"=>"Update Invoice",
 "id"=>"8"}

Спасибо за помощь.


person Steve    schedule 15.11.2012    source источник


Ответы (3)


Я нашел решение, которое, кажется, работает:

class Invoice < ActiveRecord::Base
  attr_accessible :job_name, :items_attributes, :tax1, :tax2, :subtotal

  before_save :calculate_totals


  has_many :items, :dependent => :destroy
  accepts_nested_attributes_for :items, allow_destroy: true

  private
    def calculate_totals
      self.subtotal = 0

      self.items.each do |i|
        unless i.marked_for_destruction?
          self.subtotal += (i.quantity * i.cost_per)
        end
      end

end

Ключевым является метод помеченный_для_уничтожения? В этом случае я проверял предметы, которые не были помечены для уничтожения. Вот ссылка на API рельсов, которая объясняет это: http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

Спасибо, Стив.

person Steve    schedule 15.11.2012
comment
Спасибо, что написали это решение, оно помогло мне решить мою проблему. - person widjajayd; 17.07.2014

Вы рассчитали элементы до того, как Invoice было сохранено, поэтому вычисленные элементы также были уничтожены, как в документе API есть руководство:

Обратите внимание, что модель не будет уничтожена, пока родитель не будет сохранен.

Так что вам просто нужно изменить before_save на after_save, это будет работать.

person Thanh    schedule 15.11.2012
comment
эй, Киен, я попробовал это, и он никогда не обновляет промежуточные итоги, даже если ни одна из записей не помечена для detstroy. Я должен был переместить это after_save в модель предметов? - person Steve; 15.11.2012
comment
Вы имеете в виду, что он обновляется в браузере, когда счет не был сохранен? после сохранения счета-фактуры он вычисляет правильные промежуточные итоги? - person Thanh; 15.11.2012
comment
он вообще не обновлял промежуточные итоги - person Steve; 15.11.2012
comment
Я думаю, что вы должны вызвать метод calculate_totals в контроллере счета-фактуры после создания счета-фактуры, потому что в этот момент счет-фактура уже знает все о своих элементах. В настоящее время ваш частный метод не может узнать, какие элементы удаляются в браузере. Возможно, вам нужно изменить его на защищенный. - person Thanh; 15.11.2012

person    schedule
comment
когда я попробовал это, я получил неопределенную локальную переменную или метод `params' для #‹Invoice:0x00000103d0b9d0›, доступны ли параметры в модели? Я могу добавить поднять параметр params.inspect прямо перед вызовом update_attributes, и он извлечет правильное значение, если добавить поднять тот же элемент с помощью методов calulate_totals, я получаю ту же ошибку, что и выше. - person Steve; 15.11.2012