用.first_or_initialize更新的子属性未保存-Ruby on Rails

时间:2019-07-08 15:23:46

标签: ruby-on-rails ruby ruby-on-rails-5

我有一个quote,其中有许多shipping methods。当我保存quote时,使用.first_or_initialize时运输方式的价格不会更新。我还尝试过在我的关联上设置autosave: true,如下所示:

quote.rb

has_many :shipping_methods, dependent: :destroy, autosave: true

我有一个回调,它刷新了我的送货方式及其价格(quote.rb)。

before_save :refresh_shipping_rates

def refresh_shipping_rates
  ShippingMethod.refresh_rates(self, admin = true)
end

我的ShippingMethod.refresh_rates函数(shipping_method.rb):

def refresh_rates(record, admin)
    #api call that returns a list of rates
    updated_rates.each do |i|
         rate = record.shipping_methods.where(name: i.name).first_or_initialize
         rate.price = i.price
    end
end

我的报价通过提交给update操作的表单来更新。

def update
    @quote = Quote.find(params[:id])
    @quote.update(parameters)

    if @quote.valid?

        flash[:notice] = []
        flash[:notice] << "Successfully Updated"
        render "update"
    else
        flash[:error] = []
        @quote.errors.full_messages.each do |message|
            flash[:error] << message 
        end
        render "layouts/fail"
    end

end

我假设shipping_methods的更新仅是因为它们与正在更新的父记录相关联,即使它们的任何属性都没有通过表单提交。

2 个答案:

答案 0 :(得分:2)

致电时

 rate = record.shipping_methods.where(name: i.name).first_or_initialize

shipping_method从数据库加载到与quote不相关的内存中的新对象。您应该:

  1. 更新以shipping_method关联关系加载的对象(无需调用任何从数据库获取它们的方法),或者
  2. 分别保存shipping methods

我建议您尝试1)。

答案 1 :(得分:0)

此方法应为:

def refresh_rates(record, admin)
    #api call that returns a list of rates
    updated_rates.each do |i|
         rate = record.shipping_methods.where(name: i.name).first_or_initialize
         rate.price = i.price
    end
end

收件人:

def refresh_rates(record, admin)
    #api call that returns a list of rates
    updated_rates.each do |i|
         rate = record.shipping_methods.where(name: i.name).first_or_initialize
         rate.price = i.price
         rate.save
    end
end

OR:

def refresh_rates(record, admin)
    #api call that returns a list of rates
    updated_rates.each do |i|
         rate = record.shipping_methods.where(name: i.name).first_or_initialize(price: i.price)
    end
end