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

问题描述:

A report_templatehas_manyreport_template_columns,其各自具有 nameindex属性。如何防止使用ActiveRecord中的作用域has_many嵌套创建失败?

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 

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' 

如果我删除同一命令成功的范围。

如果我将order范围替换为where范围,该命令以相同的方式失败,所以它似乎是存在范围而不是使用order具体。

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

+0

不要范围适用于ASSOCATION。它的反模式与'defual_scope'相同。看起来似乎很方便,但如果您不想稍后应用范围,会使事情变得非常困难。 http://weblog.jamisbuck.org/2015/9/19/default-scopes-anti-pattern.html – max

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

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

的API指出:inverse_of

Specifies the name of the belongs_to association on the associated object that is the inverse of this has_many association. Does not work in combination with :through or :as options. See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.

我也喜欢怎么cocoon gem话他们之所以使用它:

Rails 5 Note: since rails 5 a belongs_to relation is by default required. While this absolutely makes sense, this also means associations have to be declared more explicitly. When saving nested items, theoretically the parent is not yet saved on validation, so rails needs help to know the link between relations. There are two ways: either declare the belongs_to as optional: false , but the cleanest way is to specify the inverse_of: on the has_many. That is why we write: has_many :tasks, inverse_of: :project

+0

它应该是'belongs_to:report_template,inverse_of :: report_template_columns'(复数)?与单数我得到'ActiveRecord :: InverseOfAssociationNotFoundError:无法找到report_template(:report_template_column in ReportTemplate)',反函数',用复数我得到同样的错误在问题中。 – tommarshall

+0

糟糕,我想我错误地写了我的答案。 'inverse_of'应该放在'has_many'这一边。 – ardavis

+0

这是工作。尽管我不需要改变'create!'调用,以便'inverse_of'解决问题。如果您从答案中删除该部分,我会将其作为接受的答案。感谢您的帮助:) – tommarshall