Rails has_one :through association

Ruby on-RailsAssociationsRails ActiverecordRails Models

Ruby on-Rails Problem Overview


Rails has a has_one :through association that helps set up a one-to-one association with a third model by going through a second model. What is the real use of that besides making a shortcut association, that would otherwise be an extra step away.

Taking this example from the Rails guide:

class Supplier < ActiveRecord::Base
  has_one :account
  has_one :account_history, :through => :account
end

class Account < ActiveRecord::Base
  belongs_to :supplier
  has_one :account_history
end

class AccountHistory < ActiveRecord::Base
  belongs_to :account
end

might allow us to do something like:

supplier.account_history

which would otherwise be reached as:

supplier.account.history

If it's only for simpler access then technically there could be a one-to-one association that connects a model with some nth model going through n-1 models for easier access. Is there anything else to it that I am missing besides the shortcut?

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

  1. Logic, OK it might sound a bit weak for this but it would be logical to say that "I have a supplier who has an account with me, I want to see the entire account history of this supplier", so it makes sense for me to be able to access account history from supplier directly.

  2. Efficiency, this for me is the main reason I would use :through, simply because this issues a join statement rather than calling supplier, and then account, and then account_history. noticed the number of database calls?

  • using :through, 1 call to get the supplier, 1 call to get account_history (rails automatically uses :join to retrieve through account)

  • using normal association, 1 call to get supplier, 1 call to get account, and 1 call to get account_history

That's what I think =) hope it helps!

Solution 2 - Ruby on-Rails

I'm surprised no one has touched on Association Objects.

A has_many (or has_one) :through relationship facilitates the use of the association object pattern which is when you have two things related to each other, and that relation itself has attributes (ie a date when the association was made or when it expires).

This is considered by some to be a good alternative to the has_and_belongs_to_many ActiveRecord helper. The reasoning behind this is that it is very likely that you will need to change the nature of the association or add to it, and when you are a couple months into a project, this can be very painful if the relationship were initially set up as a has_and_belongs_to_many (the second link goes into some detail). If it is set up initially using a has_many :through relationship, then a couple months into the project it's easy to rename the join model or add attributes to it, making it easier for devs to respond to changing requirements. Plan for change.

Solution 3 - Ruby on-Rails

  • Inverse association: consider the classic situation user-membership-group. If a user can be a member in many groups, then a group has many members or users, and a user has many groups. But if the user can only be a member in one group, the group still has many members: class User has_one :group, :through => :membership but class Group has_many :members, :through => memberships. The intermediate model membership is useful to keep track of the inverse relationship.

  • Expandability: a has_one :through relationship can easy be expanded and extended to a has_many :through relationship

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAnuragView Question on Stackoverflow
Solution 1 - Ruby on-RailsStaelenView Answer on Stackoverflow
Solution 2 - Ruby on-Railsryan0View Answer on Stackoverflow
Solution 3 - Ruby on-Rails0x4a6f4672View Answer on Stackoverflow