New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow accepts_nested_attributes_for
to accept associated record attributes with custom primary keys
#48733
base: main
Are you sure you want to change the base?
Allow accepts_nested_attributes_for
to accept associated record attributes with custom primary keys
#48733
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just wanted to mention that changes in this PR treat primary_key
value as a single column though technically Rails main
allows primary_key
to be derived and configured as an Array.
However, I don't think we need to overcomplicate this PR with any changes related to composite primary keys since, we can always do a follow up
nested_attributes_possible_id_names(klass).each do |primary_key| | ||
return attributes[primary_key] if attributes[primary_key].present? | ||
end | ||
nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For some reason I really want to use find
here but not sure if it looks any better
nested_attributes_possible_id_names(klass).each do |primary_key| | |
return attributes[primary_key] if attributes[primary_key].present? | |
end | |
nil | |
pk = nested_attributes_possible_id_names(klass).find do |primary_key| | |
attributes[primary_key] | |
end | |
attributes[pk] if pk |
assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy]) unless call_reject_if(association_name, attributes) | ||
|
||
elsif attributes["id"].present? | ||
raise_nested_attributes_record_not_found!(association_name, attributes["id"]) | ||
elsif id = get_nested_attributes_id(attributes, association.klass) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unlikely it will be noticeable in the big picture but perhaps we could avoid calling get_nested_attributes_id
more than once and just derive it before all the if
statements and reuse it
unless call_reject_if(association_name, attributes) | ||
# Make sure we are operating on the actual object which is in the association's | ||
# proxy_target array (either by finding it, or adding it if not found) | ||
# Take into account that the proxy_target may have changed due to callbacks | ||
target_record = association.target.detect { |record| record.id.to_s == attributes["id"].to_s } | ||
target_record = association.target.detect { |record| record.id.to_s == get_nested_attributes_id(attributes, association.klass).to_s } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as the other comment. It look like we should be able to perform get_nested_attributes_id(attributes, association.klass).to_s
once and reuse it
Calling it multiple times makes me a little uncomfortable as it calls into nested_attributes_possible_id_names
which allocates the same ["id", :id]
array
nil | ||
end | ||
|
||
def nested_attributes_possible_id_names(klass) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we won't be able to avoid multiple calls to get_nested_attributes_id
perhaps we should consider memoizing the value
…ributes with custom primary keys
253ae65
to
be7d40c
Compare
Thanks! Updated with the suggestion for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Let's have someone from the core team to have a look
One thing I didn't mention in my previous review is that in this PR we treat primary_key
value as a single column while on main
Active Record allows primary_key
to be derived as an array. However, I don't think it is a concern as we shouldn't be doing two things (composite primary keys support & bug fix) in the same PR. So to me it's okay to ship it as is and we will address the composite primary keys support later
Thank you for the fix!
Seems like this fix is similar/interrelated to the changes in another PR #48390 |
Fixes #48714.
Currently, when we have an
accepts_nested_attributes_for
for a child relation with a custom primary key, when assigning child attributes we must use"id"
key with a value to provide a primary key, which can be confusing (as in the linked issue).Example:
Before:
After - both variants are working