Rails Relationships
Here's a brief visual tutorial to Rails relationships or "Associations". See Models and Relationships and Advanced Relationships for detailed tutorials.
has_many & belongs_to
Goal: Each category
can have many products
, and each product
can belong to one category
.
Solution: Set up a one-to-many relationship between models.
Database
Add a column for category_id
to the products table, to identify the product that a category belongs to.
Migration
rails generate migration AddCategoryIdToProducts category_id:integer
Models
belongs_to
- Tell Rails that each product belongs_to a category
class Product < ActiveRecord::Base
belongs_to :category
end
has_many
- Tell Rails that each category has_many products
class Category < ActiveRecord::Base
has_many :products
end
Code
prod1 = Product.first
prod1.category # returns prod1's category
cat1 = Category.first
cat1.products #returns collection of cat1's products
has_one & belongs_to
Goal: Each user
can have one cart
, and each cart
can belong to one user
.
Solution: Set up a one-to-one relationship between models.
Database
Add a column for user_id
to the carts table, to identify the user that a cart belongs to.
Migration
rails generate migration AddUserIdToCarts user_id:integer
Models
belongs_to
- Tell Rails that each product belongs_to a category
class Cart < ActiveRecord::Base
belongs_to :user
end
has_one
- Tell Rails that each User has_one cart.
class User < ActiveRecord::Base
has_one :cart
end
Code
user1 = User.first
user.cart # return's user1's cart
cart1 = Cart.first
cart1.user #return's cart1's user
has_many through
Goal: A user
should be able to 'like' products
. Each user could like many products, and each product could be liked by many users. Easily retrieve the products a user likes.
Solution: Set up a many-to-many relationship between models.
Database
Create a new table likes
with 2 columns: user_id
and product_id
. Each like record stores a relationship between a User and a Product.
Migration - create a Like model and table:
rails generate model Like user_id:integer product_id:integer
Models
Like uses a standard belong_to
:
class Like < ActiveRecord::Base
belongs_to :user
belongs_to :product
end
Here's a simple has_many through:
class User < ActiveRecord::Base
has_many :likes
has_many :products, through: :likes
end
The above code lets you call user.products
on a user
. Change the name of the relationship and provide a source
model:
class User < ActiveRecord::Base
has_many :likes
has_many :liked_products, through: :likes, source: :product
end
Now you can call user.liked_products
, which is clearer.
The product model uses a standard has_many
relationship:
class Product < ActiveRecord::Base
has_many :likes
end
(It doesn't currently declare a relationship to retrieve 'Liking Users' from a given product.)
Code
prod1 = Product.first
prod1.likes # returns prod1's likes
user1 = User.first
user1.likes #returns user1's likes
user1.liked_products # returns user1's liked products
Additional Relationships
has_and_belongs_to_many
has_many through
was covered above. If you know you'll never need to add any columns or methods to the like model, you can skip creating the like model and instead create a has-and-belongs-to-many-association association between users and products. You will still need to create a table to store the relationship.
has_one through
has_one :through is like has_many through
for a has_one
relationship.