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:
parent
e42cbb7d31
commit
186327f74a
1 changed files with 54 additions and 36 deletions
|
@ -709,56 +709,74 @@ class Book < ApplicationRecord
|
||||||
end
|
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
|
```ruby
|
||||||
a = Author.first
|
a = Author.first
|
||||||
b = a.books.first
|
b = a.books.first
|
||||||
a.first_name == b.author.first_name # => true
|
a.first_name == b.author.first_name # => true
|
||||||
a.first_name = 'Manny'
|
a.first_name = 'David'
|
||||||
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 == b.author.first_name # => true
|
a.first_name == b.author.first_name # => true
|
||||||
```
|
```
|
||||||
|
|
||||||
There are a few limitations to `inverse_of` support:
|
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:
|
||||||
|
|
||||||
* 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:
|
|
||||||
|
|
||||||
* `:conditions`
|
* `:conditions`
|
||||||
* `:through`
|
* `:through`
|
||||||
* `:polymorphic`
|
* `:polymorphic`
|
||||||
|
* `:class_name`
|
||||||
* `:foreign_key`
|
* `: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
|
Detailed Association Reference
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue