
A design pattern for Likes!
Many apps use this feature today. As a user you can like a post, page or even comments. Often a simple "thumbs up" is not enough. As a user of Facebook or LinkedIn you are used to select between different kind of like types.
If you also want to provide multiple types of like-buttons, or other kind of up-down-vote features you are in the right place. This short how-to shows you how to implement a Like feature with RubyOnRails.
We do not care about the views in this how-to, because it's up to you what you want to use. You can also take the ideas behind the concept easily adapt it to other frameworks.
The Like model
Let's start with model to track the user likes. Create a new model called like.rb. You can use rails generators or you can add migration and model files manually.
We need 3 things for a like model:
- Who liked? The user -> user_id
- Liked what? The reference -> polymorphic association
- What type of like? Different type of likes -> stored as integer, but could be a string, like you prefer
Database fields for a Like:
create_table :votes do |t| t.integer :reference_id t.string :reference_type t.integer :user_id t.integer :value, default: 0 t.timestamps null: false end
Active Record Class for a Like
The Like-class is pretty basic. We have a belongs_to :user and a belongs_to :reference relation. To allow one like per user per reference you can add a uniqueness validator scoped on the reference. For our example we want to provide 5 different kind of like types. So the value has to be between 0 and 4. (Devs should start counting from 0).
class Like < ActiveRecord::Base belongs_to :user belongs_to :reference, polymorphic: true validates_presence_of :value, :user, :reference validates :user_id, uniqueness: { scope: [:reference_id, :reference_type] } validates :value, inclusion: 0..4 end
Add likes to your post model
To allow your users to like your post you just have to add a has_many :likes relation to your model.
class Post < ActiveRecord::Base has_many :likes, as: :reference, dependent: :destroy # rest of your class... end
Add likes to you user model
To get all likes from the user you just have to add this relation to user.rb.
has_many :likes, dependent: :destroy
The Like Controller Class
This is just an example how to implement a controller action for like-unlike feature. If you are using GraphQL you have to put this logic into your mutation resolvers.
Create a class called LikesController under app/controllers/likes_controller.rb. This class will take care of the like-unlike logic. For liking we use create-action. Unlike is actually deleting an entry.
class LikesController < ApplicationController # e.g. your auth logic # before_filter :authenticate_user! end
Like Action (create)
Set the user id from the current_user and create a new like.
def create # prevent from liking for other users params[:like][:user_id] = current_user.id @like = Like.new(like_params) if @like.save flash[:success] = 'Thanks for liking!' else flash[:alert] = @like.errors.full_messages.join(', ') end end protected def like_params params.require(:like).permit(:value, :user_id, :reference_id, :reference_type) end
If you are paranoid you can first check if the given reference still exists in your database.
Unlike Action (destroy)
def destroy @like = current_user.likes.find(params[:id]) @like.destroy end
Like you can see, these two actions are pretty basic, but they work. You can extend the actions by implementing different kind of respond formats or other special authentication logic (e.g. cancancan).
Change my like (update)
I would not implement an extra action for changing a like. You can hook up a before_create action in your model and delete all previous likes for the reference. In my opinion it is not needed here.
Your views
It's not important in what you are coding your frontend. It might be react.js, or react.native or just the classic RubyOnRails views. The import things are:
- Make a like-component or -partial, that you can put this everywhere in your frontend.
- For liking: Present up to 5 different kind of like-emojis. For each number between 0 and 4 you show a emoji. If the user clicks on a emoji you have to make a call to the backend with the selected value.
- Unlike: Unliking is deleting a like for a user. So in your views you have to know if the user has liked that post.
Conclusion
Rails is a great framework for web development and this small example shows again how easy it is to implement business logic with rails. It's up to you how to go on from here.
I ❤️Rails,
Simon
Icons made by Freepik from www.flaticon.com