Skip to content

Instantly share code, notes, and snippets.

@gabebw
Last active August 29, 2015 14:07
Show Gist options
  • Save gabebw/78a87566df25a89e7884 to your computer and use it in GitHub Desktop.
Save gabebw/78a87566df25a89e7884 to your computer and use it in GitHub Desktop.
ActiveRecord Relations: `belongs_to` and `has_many`

belongs_to

Here's the documentation.

Let's say we have this:

class Image
  belongs_to :user
end
  • Always singular! belongs_to :user, not belongs_to :users
    • Double check, it's the #1 error students make with this.
  • Goes on the model with a foreign key, so belongs_to :user means that Image has a user_id column
  • Adds user and user= instance methods (among others), to get and set the associated user
  • Assumes that the foreign key is user_id, i.e. Image has a user_id column. belongs_to :thing would assume a thing_id column, and so on.
  • Assumes that the associated class is User, i.e. it should do User.find not Wombat.find or something.

To change the assumptions

Let's say Image has an associated User, but the foreign key isn't user_id, it's owner_id. We'd use the foreign_key option. Note that we still want a User instance when we call image.user, we're only changing the column name.

belongs_to :user, foreign_key :owner_id

OK, now let's assume that Image has a user_id column (like belongs_to :user implies), but we want to get a Wombat instance when we call image.user. We'd use the class_name option:

# "Wombat" has to be a string.
belongs_to :user, class_name: "Wombat"

You can combine the options if you need to, as well.

has_many

Here's the documentation.

Let's say we have this:

class User
  has_many :images
end
  • Always plural! has_many :images, not has_many :image
  • Does not have the foreign key; the other side of the relation has the foreign key (here, it's images).
  • Assumes that the images table has a an association_id column. Here, the association is user, so it looks for user_id.
    • Remember, user.images translates to the SQL SELECT * FROM images WHERE user_id = N, where N is user.id.
  • Assumes that it will return Image instances

To change the assumptions

Let's say that Image has an owner_id foreign key instead of user_id. So the SQL that has to be generated is (N is the user's ID):

SELECT * FROM images WHERE product_id = N
-- Instead of:
-- SELECT * FROM images WHERE user_id = N

In order for Rails to use the association correctly, you'd do:

has_many :images, foreign_key: :product_id

OK, now let's say that we want to find SpecialImages, not Images, but still call user.images. SpecialImage has a user_id foreign key, so we don't need the foreign_key option, but has_many :images will look for an Image class. To have it look for SpecialImages instead:

# Note that `class_name` uses a string, it's just how it is.
has_many :images, class_name: "SpecialImage"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment