Methods and Products
User Methods
You saw how to set up code to create likes, now it's time to improve the code with some additional methods.
like
To make things simpler, create a method in User for liking products.
Here's one way you could create the method in User:
def like(product)
Like.create(user_id: self.id, product_id:product.id)
end
Rails also lets you mention the model directly instead of the ID, so you can shorten the code:
def like(product)
Like.create(user: self, product: product)
end
likes?
Add another method to user that checks if a user likes a specific product. To do this, check if the user's liked_products includes a given product.
(To find a method that check if an item exists in a collection, see Ruby Arrays or look at Ruby's enumerable docs.)
Get the user's liked products and check if they include?
the given product:
class User < ActiveRecord::Base
#...
def likes?(product)
liked_products.include?(product)
end
end
(Note that liked_products
is equivalent to self.liked_products
, it returns all the liked_products of the user.)
validation
Can you add validations to the Like model to make sure every like has a user_id
and product_id
?
validates :user_id, presence: true
validates :product_id, presence: true
dependent relationships
If you ever delete a user, their likes will still exist in the database.
Above, user #1 is deleted, but now these 3 likes are all pointing to a user who does not exist:
To fix this issue, add the dependent: :destroy
option to the user-likes relationship:
user.rb
has_many :likes, dependent: :destroy
This will destroy all of a user's likes when the user is destroyed. So when user #1 gets deleted, his likes get deleted as well:
Complete User Model
Here's how the User model should look:
models/user.rb
class User < ActiveRecord::Base
# devise code...
has_many :likes, dependent: :destroy
has_many :products, through: :likes, source: :product
def like(product)
Like.create(user: self, product: product)
end
def likes?(product)
liked_products.include?(product)
end
end
Console Time
reload!
your Rails console and try out your new user methods, for example:
p2 = Product.second u2 = User.second u2.like(p2) u2.likes?(p2)
Product's likes
You can now get all the products that a specific user likes. Can you add a line of code to the Product model to make it easy to get all the likes for a specific product?
This is just a simple has_many
line. If a product is destroyed, the likes are no longer relevant, so add the option to destroy them as well:
class Product < ActiveRecord::Base
#..
has_many :likes, dependent: :destroy
#..
end
After adding the above code, you can now get the likes for a given product. reload!
your rails console and try it out:
prod = Product.find 1 prod.likes
Liking Users
Optional Challenge
You can now get the likes for a given product, but what should you do if you wanted to get the actual users who like a product?
Guidelines
- Add another relationship to the Product model.
- Add a relationship to the Like model.
Add the following code to the product model below has_many :likes, dependent: :destroy
:
has_many :liking_users, through: :likes, source: :user
Then add the following code to the Like model:
belongs_to :user
You can now reload your console and try getting liking_users for a given product!