如何在ActiveRecord中使用作用域has_many防止嵌套创建失败?

tom*_*all 2 ruby activerecord ruby-on-rails rails-activerecord ruby-on-rails-5

A report_template has_many report_template_columns,每个都有一个 nameindex属性。

class ReportTemplateColumn < ApplicationRecord
  belongs_to :report_template
  validates :name, presence: true
end

class ReportTemplate < ApplicationRecord
  has_many :report_template_columns, -> { order(index: :asc) }, dependent: :destroy
  accepts_nested_attributes_for :report_template_columns, allow_destroy: true
end
Run Code Online (Sandbox Code Playgroud)

report_template_columns需要由索引列进行排序。我在has_many关联范围上应用了此方法,但是这样做会导致以下错误:

> ReportTemplate.create!(report_template_columns: [ReportTemplateColumn.new(name: 'id', index: '1')])
ActiveRecord::RecordInvalid: Validation failed: Report template columns report template must exist
from /usr/local/bundle/gems/activerecord-5.1.4/lib/active_record/validations.rb:78:in `raise_validation_error'
Run Code Online (Sandbox Code Playgroud)

如果删除范围,则同一命令成功。

如果我用order作用域替换作用域,where那么命令将以相同的方式失败,因此似乎是作用域的存在而不是order特定的使用。

如何在has_many不破坏嵌套创建的情况下将范围应用于?

ard*_*vis 5

我相信您需要将:inverse_of选项添加到has_many关联中。

class ReportTemplate < ApplicationRecord
  has_many :report_template_columns, -> { order(index: :asc) },
           dependent: :destroy, inverse_of: :report_template
end
Run Code Online (Sandbox Code Playgroud)

该API指出:inverse_of

指定关联对象上的反向关联的belongs_to关联的名称has_many。不能与:through:as选项组合使用。有关更多详细信息,请参见ActiveRecord :: Associations :: ClassMethods的双向关联概述。

我还喜欢茧宝石如何表达使用它的理由:

Rails 5注意:由于Rails 5 belongs_to是默认需要的关系。尽管这绝对有道理,但这也意味着必须更明确地声明关联。在保存嵌套项目时,理论上父级尚未保存在验证中,因此Rails需要帮助来了解关系之间的联系。有两种方法:声明为belongs_toas optional: false,但是最干净的方法是inverse_of:在has_many上指定。这就是为什么我们这样写:has_many :tasks, inverse_of: :project