-
Notifications
You must be signed in to change notification settings - Fork 21.6k
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
Respect custom primary keys for nested attributes #10271
Conversation
lol, sorry about that. re-opening. |
👍 Nice find + fix. Not that I have any say in whether this gets accepted, but I'll offer a couple of changes I would make:
For item 2, I'm just assuming the fixture has the column named Like I said though, I don't get to decide these things, it's just what I'd like to see. 😄 Great work! |
unless reject_new_record?(association_name, attributes) | ||
association.build(attributes.except(*UNASSIGNABLE_KEYS)) | ||
end | ||
elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes['id'].to_s } | ||
elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes[pk_name].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.
wouldn't record.id
also become record.<primary_key>
?
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.
We could do that, but it's always safe to use id
on the record, because ActiveRecord::AttributeMethods::PrimaryKey defines the id
method to always read/write the primary key, and then actually aliases a method with the primary key name to the id
method. Obviously, this means that if we use a custom primary key name, we can't use an id
column name at all, but that's a separate issue.
Thanks for the feedback, guys, hope my responses make sense 😄 |
existing_records = if association.loaded? | ||
association.target | ||
else | ||
attribute_ids = attributes_collection.map {|a| a['id'] || a[:id] }.compact | ||
attribute_ids.empty? ? [] : association.scope.where(association.klass.primary_key => attribute_ids) | ||
attribute_ids = attributes_collection.map {|a| a[pk_name] || a[pk_name.to_sym] }.compact |
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.
Do we still need this to_sym
- I think the attributes hash is pretty much guaranteed to be using string keys
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.
Sorry, we do - it's the user supplied hash. Got confused there for a minute 😄
@chadmoone why doesn't the |
@pixeltrix So if the nested attribute hash does not include a key I think that answers your question, but let me know if I'm missing it. |
@chadmoone thanks, understand now. |
It doesn't make sense to require using 'id' for the primary key in these hashes, when we explicitly allow for the specification of primary keys.
Last update there was just clarifying a bit in the documentation, but went ahead and squashed. |
ActiveRecord allows us to specify custom primary keys, but does not properly accept them for nested attributes.
For example, with the models:
The primary key stored in the database (and presumably other related applications) as
uuid
, and the object is serialized as such:To create a new instance of the model itself:
However, using the correct primary key in an update to nested attributes will fail in multiple ways:
Instead, we currently need to set up a hash like so:
Forcing the use of the arbitrary key
id
doesn't seem to make a lot of sense, and it forces anything interacting with Rails (and sometimes even Rails itself) to specially modify the object hash to use an otherwise unknown key.The only tests that I needed to modify were two that specifically deal with custom primary keys in nested attributes (as these were verifying the old behavior), and all other tests pass.
Please let me know if you have any issues or if you think there is a better way to go about this.