Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Rails, what is the difference using "has_many with belongs_to" vs "has_many with has_one"?

For example, in

class Student < ActiveRecord::Base
  has_many :awards
end

class Awards < ActiveRecord::Base
  belongs_to :student
end

the above should be the correct usage, but what if we use

class Student < ActiveRecord::Base
  has_many :awards
end

class Awards < ActiveRecord::Base
  has_one :student
end

doesn't the above also make possible student.awards as an array of Award objects, and award.student as a Student object which is the recipient of the award, so works the same way as the method at the top of post?

like image 865
nonopolarity Avatar asked Sep 15 '10 02:09

nonopolarity


2 Answers

has_one is used in case of a one-to-one relationship, not in one-to-many relationships.

Correct use of has_one:

class Student < ActiveRecord::Base
  has_one :id_card
end

class IdCard < ActiveRecord::Base
  belongs_to :student
end
like image 77
Mischa Avatar answered Sep 29 '22 08:09

Mischa


The two examples are not equivalent.

has_many and belongs_to work as a pair where there is a 'many to one' relationship.

In the database this would look like:

**Students**
Name
Email
...

**Awards**
Name
student_id  <-- !IMPORTANT!
...

Each Student has many awards hence has_many :awards Each Award 'belongs to' a Student hence belongs_to :student

Notice that the belongs_to is applied to the table with the foreign key student_id. This is important.

OK - so what happens where there is a 'one to one' relationship?

If each student could only have a single award then the database tables could look exactly the same but the model should not be able to return a collection of items.

This is where we need the has_one declaration. This would be applied to the Student model in this case. Why? Because the relationship is the same in both directions but Active Record needs to know where to find the foreign key.

If the database tables were the other way around with each Student having an award_id then the Student would get the belongs_to and the Award would get the has_one.

Hope that makes it clear?

It does seem a little odd to be that a student could 'belong to' an award if you use natural language. But that is how the rails active record domain specific language is written.

It gets even more unnatural sounding when you look at the 'many to many' relationship with 'has_many_and_belongs_to'. Here there is a joining table which site between your main tables like

students_awards
student_id
award_id

In this situation neither the Students nor the Awards table have a foreign key but both will carry the has_many_and_belongs_to :other_table declaration. Both tables are able to join to multiple rows of the other. Each Student can have more than one Award. Each Award can be applied to many Students.

The has_one declaration is only used where there is a 'one-to-one' relationship and the table it applies to does not have the foreign key.

like image 35
Richard Washington Avatar answered Sep 29 '22 06:09

Richard Washington