如何在不再次调用 .save 的情况下将子记录的 ID 保存在父记录中?
How can I save the id of a child record in the parent without calling .save again?
我有一个问题,在 Rails 5.1 之前,遗留代码在 after_save
回调中调用 .save
,但由于 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
基于 my_model.id
创建具有正确 other_model.my_model_id
的初始 OtherModel
实例。
但是,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
我能够在 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)
注意:我不会向任何没有被遗留代码强加给他们的人推荐这种初始化内部回调的风格。这感觉很脆弱。
我有一个问题,在 Rails 5.1 之前,遗留代码在 after_save
回调中调用 .save
,但由于 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
基于 my_model.id
创建具有正确 other_model.my_model_id
的初始 OtherModel
实例。
但是,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
我能够在 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)
注意:我不会向任何没有被遗留代码强加给他们的人推荐这种初始化内部回调的风格。这感觉很脆弱。