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_commitgem的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'

10-01 19:00
查看更多