Rails 7 allows constructors (build_association and create_association) on has_one :through associations

Akanksha Jain avatar

Akanksha Jain

April 6, 2021

This blog is part of our  Rails 7 series.


What are build_association and create_association constructors?

When we declare either a belongs_to or has_one association, the declaring class automatically gains the following methods related to the association:

  1. build_association(attributes = {})
  2. create_association(attributes = {})

In the above methods _association is replaced with the symbol(association name) passed as the first argument while declaring the associations. For example:

class Book < ApplicationRecord
  belongs_to :author
end

@book.build_author(name: 'John Doe', email: '[email protected]')
#=> Returns a new Author object, instantiated with the passed attributes
#=> Links through the book's object foreign key
#=> New author object won't be saved in the database

@book.create_author(name: 'John Doe', email: '[email protected]')
#=> Returns a new Author object, instantiated with the passed attributes
#=> Links through the book's object foreign key
#=> The new author object will be saved in the database after passing all of the validations specified on the Author model

Before Rails 7

The build_association and create_association constructors were only supported by belongs_to and has_one associations.

Consider the example below. We have a model, Member, that has a has_one association with the CurrentMembership model. It also has a has_one :through association with the Club model.

class Member < ApplicationRecord
  has_one :current_membership
  has_one :club, through: :current_membership
end

@member.build_club
#=> NoMethodError (undefined method `build_club' for #<Member:0x00007f9ea2ebd3e8>)
#=> Did you mean?  build_current_membership

@member.create_club
#=> NoMethodError (undefined method `create_club' for #<Member:0x00007f9ea2ebd3e8>)
#=> Did you mean?  create_current_membership

After Rails 7

Users are allowed to use constructors (build_association and create_association) on has_one :through associations along with belongs_to and has_one associations.

class Member < ApplicationRecord
  has_one :current_membership
  has_one :club, through: :current_membership
end

@member.build_club
#=> #<Club:0x00007f9ea01a8ce0>

@member.create_club
#=> #<Club:0x00007f9ea01a8ce0>

Check out this pull request for more details.

Follow @bigbinary on X. Check out our full blog archive.