194

What is the difference between a belongs_to and a has_one?

Reading the Ruby on Rails guide hasn't helped me.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Blankman
  • 259,732
  • 324
  • 769
  • 1,199

8 Answers8

299

They essentially do the same thing, the only difference is what side of the relationship you are on. If a User has a Profile, then in the User class you'd have has_one :profile and in the Profile class you'd have belongs_to :user. To determine who "has" the other object, look at where the foreign key is. We can say that a User "has" a Profile because the profiles table has a user_id column. If there was a column called profile_id on the users table, however, we would say that a Profile has a User, and the belongs_to/has_one locations would be swapped.

here is a more detailed explanation.

ryeguy
  • 65,519
  • 58
  • 198
  • 260
  • ok makes sense, has_a is property, while a belongs is more of a relation. – Blankman Sep 28 '10 at 01:48
  • 86
    So to say it really short: `Product belongs_to Shop` means `products` table has `shop_id` column – Yo Ludke Sep 24 '14 at 12:31
  • 1
    @ryeguy, what about if this is a self join relationship? – Arian Faurtosh Apr 01 '20 at 01:44
  • 1
    As far as I understand: Also remember that Rails will try to find _id column in the database in table of class where you write belongs_to. For example if Question belongs_to :answer Rails will try to find column answer_id in Question table. Or if you write belongs_to :cool_answer Rails will try to find column cool_answer_id. So rails just picks the name from belongs_to and tries to add _id. If there's no such column, Rails will raise an exception or something like this. – bolt Apr 22 '21 at 21:55
  • An easy way to remember which is which is that `has_one` puts the foreign key in the same place as `has_many` _(but only expecting a single instance association)_. – karmakaze Aug 17 '23 at 22:11
85

It's about where the foreign key sits.

class Foo < AR:Base
end
  • If foo belongs_to :bar, then the foos table has a bar_id column
  • If foo has_one :bar, then the bars table has a foo_id column

On the conceptual level, if your class A has a has_one relationship with class B then class A is the parent of class B hence your class B will have a belongs_to relationship with class A since it is the child of class A.

Both express a 1-1 relationship. The difference is mostly where to place the foreign key, which goes on the table for the class declaring the belongs_to relationship.

class User < ActiveRecord::Base
  # I reference an account.
  belongs_to :account
end

class Account < ActiveRecord::Base
  # One user references me.
  has_one :user
end

The tables for these classes could look something like:

CREATE TABLE users (
  id int(11) NOT NULL auto_increment,
  account_id int(11) default NULL,
  name varchar default NULL,
  PRIMARY KEY  (id)
)

CREATE TABLE accounts (
  id int(11) NOT NULL auto_increment,
  name varchar default NULL,
  PRIMARY KEY  (id)
)
cweston
  • 11,297
  • 19
  • 82
  • 107
9

has_one and belongs_to generally are same in a sense that they point to the other related model. belongs_to make sure that this model has the foreign_key defined. has_one makes sure that the other model has_foreign key defined.

To be more specific, there are two sides of relationship, one is the Owner and other is Belongings. If only has_one is defined we can get its Belongings but cannot get the Owner from the belongings. To trace the Owner we need to define the belongs_to as well in the belonging model.

Shiva
  • 11,485
  • 2
  • 67
  • 84
4

One additional thing that I want to add is, suppose we have the following models association.

class Author < ApplicationRecord
  has_many :books
end

If we only write the above association, then we can get all books of a particular author with

@books = @author.books

but, for a particular book, we can't get the corresponding author with

@author = @book.author

To make the above code work we need to add an association to the Book model as well, like this

class Book < ApplicationRecord
  belongs_to :author
end

This will add method 'author' to the Book model. For mode details see guides

tmr08c
  • 77
  • 1
  • 8
Somesh Sharma
  • 529
  • 5
  • 7
1

has_one

  • This method should only be used if the other class contains the foreign key.

belongs_to

  • This method should only be used if the current class contains the foreign key.
Kaiwen Luo
  • 370
  • 4
  • 10
1

As many (all?) other answers have pointed out, it's all about where the foreign key is stored.

But that's not necessarily very memorable, so this way of thinking about it may help you:

  • if you want to keep track of something you own, you might write your name on your possession (such as having your Air Pods or iPhone engraved with your name)
  • but you never, on the other hand, have the name of your iPhone or Air Pods tattooed on your body.

Therefore the foreign key (a reference to the owner) always goes on the thing (record) that is owned, not a record of the possession on the owner.

iconoclast
  • 21,213
  • 15
  • 102
  • 138
0

From a simplicity standpoint, belongs_to is better than has_one because in has_one, you would have to add the following constraints to the model and table that has the foreign key to enforce the has_one relationship:

  • validates :foreign_key, presence: true, uniqueness: true
  • add a database unique index on the foreign key.
konyak
  • 10,818
  • 4
  • 59
  • 65
0

Here's the most reliable memory tool I use to remember the direction of has_many/one and belongs_to:

You write your name on the stuff that belongs to you. Your notebook or driver's license has your name written on it. You might have many notebooks and one driver's license...but all of them belong to only one person.

A child record that belongs to a parent/owning record always has the name of the owning record written on it. That is, child.owner_id is written on the child record, which belongs to the parent record.

The parent record has nothing written on it to identify the child records that has_many of. Just like you don't tattoo book titles or license numbers on your body.

David Hempy
  • 5,373
  • 2
  • 40
  • 68