如何在不再次调用.save的情况下将子记录的ID保存在父记录中?

时间:2019-05-30 13:11:59

标签: ruby-on-rails associations rails-activerecord ruby-on-rails-5.2 ruby-on-rails-5.1

我遇到一个问题,即遗留代码在.save回调中调用after_save直到Rails 5.1,但是由于saved_change_to_attribute如何替换attribute_changed?中的after_回调,则两次调用.save.save影响.changes)是一个问题。

我现在需要复制相同的行为,而无需两次调用.save

在我的Rails 5.1.7应用程序中(准备5.2升级):

class OtherModel < ApplicationRecord
  belongs_to :my_model, inverse_of: :other_model_history
end

class MyModel < ApplicationRecord
  has_many :other_model_history, class_name: 'OtherModel', inverse_of: :my_model
  belongs_to :latest_other_model, class_name: 'OtherModel'
  before_create :initialize_first_other_model

  def initialize_first_other_model
    initial_other = OtherModel.new(name: 'initial')
    other_model_history << initial_other
    latest_other_model = initial_other
    # When it finally reaches save (this is before_create) I want ActiveRecord to know
    # to save the ID of initial_other in latest_other_model_id ... but it doesn't
  end
end

调用MyModel.new.save时,initialize_other_model将基于OtherModel使用正确的other_model.my_model_id创建初始my_model.id实例。

但是,my_model.latest_other_model_id为零。尽管 latest_other_model正确引用了initial_other对象。

如何告诉ActiveRecord必须设置my_model.latest_other_model_id = initial_other.id

编辑:带有ActiveRecord::Base.logger = Logger.new(STDOUT)

DEBUG -- :   SQL (0.3ms)  INSERT INTO "my_models" ("created_at", "updated_at") VALUES (?, ?)  [["created_at", "2019-05-31 06:12:27.006455"], ["updated_at", "2019-05-31 06:12:27.006455"]]
DEBUG -- :   SQL (0.1ms)  INSERT INTO "other_models" ("my_model_id", "name", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["my_model_id", 3], ["name", "initial"], ["created_at", "2019-05-31 06:12:27.015472"], ["updated_at", "2019-05-31 06:12:27.015472"]]
DEBUG -- :    (1.5ms)  commit transaction

您会看到首先插入MyModel,没有other_model,然后插入OtherModel,其ID为MyModel。我希望Rails也知道然后插入my_models.latest_other_model_id而不调用.save

1 个答案:

答案 0 :(得分:0)

我能够在after_save中使用update_column。这样会将引用从my_model保存到other_model,而不会影响saved_changes。我的回叫现在是

before_create:

  initial_other = OtherModel.new(name: 'initial')
  other_model_history << initial_other

after_save:

update_column('latest_other_model_id', other_model_history.last.id)

注意:我不建议这种样式的回调内部初始化不给任何遗留代码强加给他们的人。这感觉很脆弱。