1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Clarify Bi-directional Associations docs

Rails automatically finds bi-directional associations between models
with well-named associations. However, when using non-standard naming,
you have to use :inverse_of to explicitly tell Rails about the bi-
directional association.

With reference to #27516

[ci skip]
This commit is contained in:
David Sherline 2017-01-01 12:13:48 -06:00 committed by David Sherline
parent e42cbb7d31
commit 186327f74a
No known key found for this signature in database
GPG key ID: 233EF292850B2E6E

View file

@ -709,56 +709,74 @@ class Book < ApplicationRecord
end
```
By default, Active Record doesn't know about the connection between these associations. This can lead to two copies of an object getting out of sync:
Active Record will attempt to automatically identify that these two models share a bi-directional association based on the association name. In this way, Active Record will only load one copy of the `Author` object, making your application more efficient and preventing inconsistent data:
```ruby
a = Author.first
b = a.books.first
a.first_name == b.author.first_name # => true
a.first_name = 'Manny'
a.first_name == b.author.first_name # => false
```
This happens because `a` and `b.author` are two different in-memory representations of the same data, and neither one is automatically refreshed from changes to the other. Active Record provides the `:inverse_of` option so that you can inform it of these relations:
```ruby
class Author < ApplicationRecord
has_many :books, inverse_of: :author
end
class Book < ApplicationRecord
belongs_to :author, inverse_of: :books
end
```
With these changes, Active Record will only load one copy of the author object, preventing inconsistencies and making your application more efficient:
```ruby
a = Author.first
b = a.books.first
a.first_name == b.author.first_name # => true
a.first_name = 'Manny'
a.first_name = 'David'
a.first_name == b.author.first_name # => true
```
There are a few limitations to `inverse_of` support:
* They do not work with `:through` associations.
* They do not work with `:polymorphic` associations.
* They do not work with `:as` associations.
* For `belongs_to` associations, `has_many` inverse associations are ignored.
Every association will attempt to automatically find the inverse association
and set the `:inverse_of` option heuristically (based on the association name).
Most associations with standard names will be supported. However, associations
that contain the following options will not have their inverses set
automatically:
Active Record supports automatic identification for most associations with standard names. However, Active Record will not automatically identify bi-directional associations that contain any of the following options:
* `:conditions`
* `:through`
* `:polymorphic`
* `:class_name`
* `:foreign_key`
For example, consider the following model declarations:
```ruby
class Author < ApplicationRecord
has_many :books
end
class Book < ApplicationRecord
belongs_to :writer, class_name: 'Author', foreign_key: 'author_id'
end
```
Active Record will no longer automatically recognize the bi-directional association:
```ruby
a = Author.first
b = a.books.first
a.first_name == b.writer.first_name # => true
a.first_name = 'David'
a.first_name == b.writer.first_name # => false
```
Active Record provides the `:inverse_of` option so you can explicitly declare bi-directional associations:
```ruby
class Author < ApplicationRecord
has_many :books, inverse_of: 'writer'
end
class Book < ApplicationRecord
belongs_to :writer, class_name: 'Author', foreign_key: 'author_id'
end
```
By including the `:inverse_of` option in the `has_many` association declaration, Active Record will now recognize the bi-directional association:
```ruby
a = Author.first
b = a.books.first
a.first_name == b.writer.first_name # => true
a.first_name = 'David'
a.first_name == b.writer.first_name # => true
```
There are a few limitations to `:inverse_of` support:
* They do not work with `:through` associations.
* They do not work with `:polymorphic` associations.
* They do not work with `:as` associations.
Detailed Association Reference
------------------------------