A report_template
has_many
report_template_columns
, which each have a
name
and an index
attribute.
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
The report_template_columns
need to be ordered by the index column. I'm applying this with a scope on the has_many
association, however doing so causes the following error:
> 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'
If I remove the scope the same command succeeds.
If I replace the order
scope with where
scope that command fails in the same way, so it seems to be the presence of the scope rather than the use of order
specifically.
How can I apply a scope to the has_many
without breaking the nested creation?
I believe you need the :inverse_of
option added to the has_many
association.
class ReportTemplate < ApplicationRecord
has_many :report_template_columns, -> { order(index: :asc) },
dependent: :destroy, inverse_of: :report_template
end
The api states that :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.
I also like how the cocoon gem words their reason for using it:
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 thebelongs_to
asoptional: false
, but the cleanest way is to specify theinverse_of:
on the has_many. That is why we write:has_many :tasks, inverse_of: :project
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With