在OpenProject应用程序中,我们有两个模型:
CustomField
class CustomField < ActiveRecord::Base
has_many :custom_options, -> { order(position: :asc) }, dependent: :delete_all
accepts_nested_attributes_for :custom_options
...
end
CustomOption
class CustomOption < ActiveRecord::Base
belongs_to :custom_field, touch: true
...
end
然后在custom field controller中,我们通过mass assignment修改自定义字段的选项并保存记录:
@custom_field.attributes = get_custom_field_params
if @custom_field.save
...
由于在
touch: true
中的custom_field
关联上配置了CustomOption
,因此我希望自定义字段的updated_at
属性在此时更新,但这不会发生。日志不显示任何类似于UPDATE custom_fields SET update_at = ....
的sql请求。无论是添加自定义选项还是修改自定义选项,对自定义选项本身所做的更改都将正确持久化。调试显示:
使用
custom_field.custom_options.build
和随后的custom_field.save
时的相同错误行为使用
custom_field.custom_options.create
时所需的行为使用
CustomOption.create custom_field: x
时所需的行为使用
custom_field.custom_option[x].destroy
时所需的行为我知道我可以通过定义
after_save
回调来解决这个问题,但是这种行为真的让我很恼火,因为它是意外的。上述行为是否符合要求并记录在案?如果是,我在哪里可以找到这些信息?
最佳答案
问题是,如果父模型有任何after_commit
回调(可能还有其他回调),:touch
在自动保存关联记录时停止工作,即使回调没有执行任何操作。
您的CustomField
模型有来自after_commit
gem的acts_as_list
回调。这会中断:touch
。
有一个类似的问题https://github.com/rails/rails/issues/26726。这个问题与accepts_nested_attributes_for
有关,但我确信accepts_nested_attributes_for
与此无关,至少在您的情况下是这样。
由问题作者(@ulferts)补充:
对inverse_of: 'custom_field'
中的custom_options
关联定义CustomField
似乎由于未知的原因绕过了这个问题。
has_many :custom_options,
-> { order(position: :asc) },
dependent: :delete_all,
inverse_of: 'custom_field'