Before Rails 6.1, we could only traverse the object chain in one direction - from has_many to belongs_to. Now we can traverse the chain bi-directionally.
inverse_of option, both in
used to specify the name of the inverse association.
Let's see an example.
1class Author < ApplicationRecord 2 has_many :books, inverse_of: :author 3end 4 5class Book < ApplicationRecord 6 belongs_to :author, inverse_of: :books 7end
Before Rails 6.1
has_many to belongs_to inversing
1irb(main):001:0> author = Author.new 2irb(main):002:0> book = author.books.build 3irb(main):003:0> author == book.author 4=> true
In the above code,
first we created the
author and then
book instance through the
In line 3,
we traverse the object chain
back to the author using the
belongs_to association method
on the book instance.
belongs_to to has_many inversing
1irb(main):001:0> book = Book.new 2irb(main):002:0> author = book.build_author 3irb(main):003:0> author.books 4=> #<ActiveRecord::Associations::CollectionProxy >
In the above case,
we created the
book instance and then
we created the
author instance using
the method added by
But when we tried to traverse the object chain
we got an empty collection
instead of one with the
After changes in Rails 6.1
belongs_to inversing can now be traversed
in the same way as the
1irb(main):001:0> book = Book.new 2irb(main):002:0> author = book.build_author 3irb(main):003:0> author.books 4=> #<ActiveRecord::Associations::CollectionProxy [#<Book id: nil, author_id: nil, created_at: nil, updated_at: nil>]>
Here we get the collection with the
instead of an empty collection.
We can also verify using a test.
1class InverseTest < ActiveSupport::TestCase 2 3 def test_book_inverse_of_author 4 author = Author.new 5 book = author.books.build 6 7 assert_equal book.author, author 8 end 9 10 def test_author_inverse_of_book 11 book = Book.new 12 author = book.build_author 13 14 assert_includes author.books, book 15 end 16end
In previous Rails versions, the test cases would fail.
1# Running: 2 3.F 4Failure: 5InverseTest#test_author_inverse_of_book 6 7Expected #<ActiveRecord::Associations::CollectionProxy > to include #<Book id: nil, author_id: nil, created_at: nil, updated_at: nil>. 8 9Finished in 0.292532s, 6.8369 runs/s, 10.2553 assertions/s. 102 runs, 3 assertions, 1 failures, 0 errors, 0 skips
In Rails 6.1, both the tests will pass.
1# Running: 2 3.. 4 5Finished in 0.317668s, 6.2959 runs/s, 9.4438 assertions/s. 62 runs, 3 assertions, 0 failures, 0 errors, 0 skips
Check out this pull request for more details.