Need help understanding this code, as what to my knowledge I know "<<" append to a collection but here it saves the record correctly, how come it does without calling .save method?
#user.rb
has_many :saved_properties, through: :property_saves, source: :property
#users_controller.rb
def update
if @user.saved_properties << Property.find(params[:saved_property_id])
render plain: "Property saved"
end
In the has_many
documentation it says:
Adds one or more objects to the collection by setting their foreign keys to the collection's primary key. Note that this operation instantly fires update SQL without waiting for the save or update call on the parent object, unless the parent object is a new record.
Maybe looking at the source code will help you. This is my trail of searches based on the <<
method in activerecord
:
def <<(*records)
proxy_association.concat(records) && self
end
rails/collection_proxy.rb at 5053d5251fb8c03e666f1f8b765464ec33e3066e · rails/rails · GitHub
def concat(*records)
records = records.flatten
if owner.new_record?
load_target
concat_records(records)
else
transaction { concat_records(records) }
end
end
rails/collection_association.rb at 5053d5251fb8c03e666f1f8b765464ec33e3066e · rails/rails · GitHub
def concat_records(records, should_raise = false)
result = true
records.each do |record|
raise_on_type_mismatch!(record)
add_to_target(record) do |rec|
result &&= insert_record(rec, true, should_raise) unless owner.new_record?
end
end
result && records
end
rails/collection_association.rb at 5053d5251fb8c03e666f1f8b765464ec33e3066e · rails/rails · GitHub
def insert_record(record, validate = true, raise = false)
set_owner_attributes(record)
set_inverse_instance(record)
if raise
record.save!(validate: validate)
else
record.save(validate: validate)
end
end
https://github.com/rails/rails/blob/5053d5251fb8c03e666f1f8b765464ec33e3066e/activerecord/lib/active_record/associations/has_many_association.rb#L32
def insert_record(record, validate = true, raise = false)
ensure_not_nested
if record.new_record? || record.has_changes_to_save?
if raise
record.save!(validate: validate)
else
return unless record.save(validate: validate)
end
end
save_through_record(record)
record
end
https://github.com/rails/rails/blob/5053d5251fb8c03e666f1f8b765464ec33e3066e/activerecord/lib/active_record/associations/has_many_through_association.rb#L38
As you can see, in the end, it does call the save
method.
Disclaimer: I'm not that familiar with Rails souce code, but you have interesting question.
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