4

Rails 7 allows constructors on has_one :through associations

 3 years ago
source link: https://blog.saeloun.com/2021/04/27/rails-7-allow-constructor-in-has-one-through
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Rails 7 allows constructors on has_one :through associations

Apr 27, 2021 , by Mayank Khanna 1 minute read

When we declare a belongs_to association, the declaring class automatically gains build_association and create_association methods.

For example, given the declaration:

class Book < ApplicationRecord
  belongs_to :author
end

Each instance of the Book model will have build_author and create_author methods.

Now let’s consider the following models.

# app/models/supplier.rb
class Supplier < ApplicationRecord
  has_one :account
  has_one :account_history, through: :account
end
# app/models/account.rb
class Account < ApplicationRecord
  belongs_to :supplier
  has_one :account_history
end
# app/models/account_history.rb
class AccountHistory < ApplicationRecord
  belongs_to :account
end

To create a supplier account, we can call create_account on the Supplier object as shown below:

Supplier.first.create_account

# Supplier Load  (0.5ms) SELECT "suppliers".* FROM "suppliers" ORDER BY "suppliers"."id" ASC LIMIT $1  [["LIMIT", 1]]

# Account Load  (0.5ms) SELECT "accounts".* FROM "accounts" WHERE "accounts"."supplier_id" = $1 LIMIT $2
[["supplier_id", "6700d0ba-b8ed-4ff5-bb69-c57e7ea7f285"], ["LIMIT", 1]]

The direct association of has_one: :account works as expected. But when we try to create AccountHistory, we get the below error:

Supplier.first.create_account_history

# Supplier Load  (0.5ms) SELECT "suppliers".* FROM "suppliers" ORDER BY "suppliers"."id" ASC LIMIT $1  [["LIMIT", 1]]

NoMethodError: undefined method `create_account_history' for #<Supplier:0x00007f949d6016c8>

As we can see, the create_account_history method is missing when we created the has_one :through relationship.

Before:

Before Rails 7, to fix the above issue, we can add a method create_account_history to the Supplier model.

class Supplier < ApplicationRecord
  has_one :account
  has_one :account_history, through: :account

  def create_account_history
    account = self.account
    account.create_account_history
  end
end

This change works as expected, but we would end up writing similar methods for all our has_one :through associations.

After:

To resolve the above issue, Rails 7 allows build_association and create_association on has_one :through associations.

AccountHistory can be created via Supplier object as shown below.

Supplier.first.create_account_history

# AccountHistory Create (1.3ms)  INSERT INTO "account_histories" ("account_id", "user_id") VALUES ($1, $2) RETURNING "id" [["account_id", "5d671a08-1513-442a-8cfa-ac00e128d423"], ["user_id", "24571aff-3456-442a-8cfa-aerte128d423"], ["organization_user_id""6700d0ba-b8ed-4ff5-bb69-c57e7ea7f285"], ["created_at", "2021-04-09 06:26:59.002535"], ["updated_at", "2021-04-09 06:26:59.002535"]]

Similarly, build_account_history will work and, it will not throw a NoMethodError exception.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK