Reputation: 43949
(source: rubyonrails.org)
Why they are using has_one:through here. We can do the same with has_one only. What's the need of making a new class. Can you give me any good example?
Here is the link for the original example from Rails guide
EDIT
We can do the same thing in this way what's the use of making it a has_one:through
class Supplier < ActiveRecord::Base
has_one :account
end
class Account < ActiveRecord::Base
belongs_to :supplier // add a another column credit_rating in accounts table
end
Upvotes: 4
Views: 2281
Reputation: 115372
The has_one :through
association is being used because the join model (AccountHistory
) contains additional information related to the association between Supplier
and Account
i.e. a credit rating.
This example in the Rails guide is quite poorly chosen because it doesn't make it obvious why using has_one :through
is better than using has_one
with a credit_rating
attribute on the Account
model.
You should use the has_one :through
or has_many :through
associations when you need extra attributes on the join model that logically don't belong on the other models that form the association. A classic example is modelling the lending of books to users within a library. The date and duration of the book loan belong in the (loan) join model because logically they're not attributes that belong to the user or the book. In this case the use of a has_many :through
association would be appropriate.
Upvotes: 2
Reputation: 50057
I think in this case it depends how you design your databasemodel. The advantage of Rails is, should you work with some legacy database, it can cope with almost all relation types. And in this case you would use the :has_one :through, because your database tables are modeled in such a way.
The advantages of using three models as proposed: there is a clean seperation between the Account and the AccountHistory. While you could model Account and AccountHistory as one combined model, there is no need. This might not seem as useful in such a small example, but for instance:
Upvotes: 1
Reputation: 11596
There are cases where you might not want to add a specific field to a table. In your example you really only need one table as you can just add account_number
and credit_ranking
to the suppliers
table. But sometimes it's a good idea to store the data across several tables. Then you have to use the has_one
(one-to-one) relationship.
In your example you could also just add the attribute supplier_id
to account_histories
and replace has_one :account_history, :through account
with just has_one :account_history
but that would be redundant and also complicate your code as you would need to make sure that you don't change one attribute and forget to update the other one.
UPDATE:
If you don't add the supplier_id
attribute to account_histories
then Rails won't be able to determine which row from that table belongs to which supplier. The only way to find that out is to look in the related accounts
table. Without accounts
you can't determine which account_history
belongs to a supplier as the accounts_histories
table doesn't have any foreign keys for the suppliers
table.
To get the account_history
for a supplier without the :through
option you would have to do this:
Supplier.find(id).account.account_history
:through
allows you to replace it with this:
Supplier.find(id).account_history
As you've written in your update you could add the credit_ranking
attribute to accounts
and have only two tables. That would be even more simple but you just might want not to store that attribute in the same table (because maybe you already have lots of other attributes and don't want to add even more of them).
Upvotes: 1
Reputation: 16425
Because by using has_one :through
you can add more attributes to Account
Upvotes: 1