rails/rails — pull request #10271 by chadmoone (2013-04-19 20:01:18+00:00)
Title: Respect custom primary keys for nested attributes

ActiveRecord allows us to specify custom primary keys, but does not properly accept them for nested attributes.

For example, with the models:

```ruby
class Deck < ActiveRecord::Base
has_many :cards, autosave: true
accepts_nested_attributes_for :cards, allow_destroy: true
end

class Card < ActiveRecord::Base
self.primary_key = "uuid"
belongs_to :deck
end
```

The primary key stored in the database (and presumably other related applications) as `uuid`, and the object is serialized as such:
```ruby
my_deck.cards.inspect
# => [{"uuid":"abcd","content":"Hello","deck_id":14,"created_at":"2013-04-17T22:05:09.623Z","updated_at":"2013-04-17T22:05:09.679Z"},{"uuid":"efgh","content":"World!","deck_id":14,"created_at":"2013-04-17T22:05:09.626Z","updated_at":"2013-04-17T22:05:09.681Z"}]

my_deck.cards.to_json
#=> [{"uuid":"abcd","content":"Hello","deck_id":14,"created_at":"2013-04-17T22:05:09.623Z","updated_at":"2013-04-17T22:05:09.679Z"},{"uuid":"efgh","content":"World!","deck_id":14,"created_at":"2013-04-17T22:05:09.626Z","updated_at":"2013-04-17T22:05:09.681Z"}]
```

To create a new instance of the model itself:
```ruby
my_deck.cards.create(uuid:"abcdefg", content: "Sup?")
```

However, using the correct primary key in an update to nested attributes will fail in multiple ways:
```ruby
# Can't destroy nested objects
my_deck.update([{uuid:"abcd",content:"Hello", _destroy: true}},
{uuid:"efgh",content:"World!", _destroy: true}])
my_deck.cards.inspect
#=> [{"uuid":"abcd","content":"Hello","deck_id":14,"created_at":"2013-04-17T22:05:09.623Z","updated_at":"2013-04-17T22:05:09.679Z"},{"uuid":"efgh","content":"World!","deck_id":14,"created_at":"2013-04-17T22:05:09.626Z","updated_at":"2013-04-17T22:05:09.681Z"}]

# Attempting to modify an object creates a new one,
# with the same primary key value (which will fail)
my_deck.update([{uuid:"abcd",content:"Something"}},
{uuid:"efgh",content:"Else!"}])
#=> Throws ActiveRecord::RecordNotUnique error
```
Instead, we currently need to set up a hash like so:
```ruby
my_deck.update([{uuid:"abcd",content:"All alone :("}},
{uuid:"efgh",content:"Else!", _destroy: true}])
my_deck.cards.inspect
#=> [{"uuid":"abcd","content":"All alone :(","deck_id":14,"created_at":"2013-04-17T22:05:09.623Z","updated_at":"2013-04-17T22:05:09.679Z"}]
```

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.