Add checkbox to edit bool value of user in devise in Rails - ruby-on-rails

I have created a user using devise gem. I have added a column admin to the User table which has boolean value. Now what I need is to add checkboxes after every user in users_page and give a feature so that when the checkbox is checked the value of admin column changes to true. How can I add the functionality?
users_controller.rb
class UsersController < ApplicationController
def users_page
#users = User.all
end
def change_user_role
#user = User.find(params[:id])
format.html { redirect_to users, notice: 'Role changed successfully' }
end
def destroy
#user = User.find(params[:id])
#user.destroy
if #user.destroy
redirect_to root_url, notice: "User deleted."
end
end
end
users_page.html.erb
<h1>Users</h1>
<% #users.each do |user| %>
<h5><%= user.email %></h5>
<%= user.admin %>
<%= form_tag({controller: "users", action: "change_user_role"}, method: "get") do %>
<%= check_box_tag(:admin, checked: false) %>
<p><%= submit_tag 'Submit Answer' %></p>
<% end %>
<br>
<%= link_to "Destroy", admin_destroy_user_path(user), method: :delete, data: { confirm: "You sure?" } %>
<% end %>
routes.rb
Rails.application.routes.draw do
root to: 'pages#home'
get 'users/users_page'
devise_for :users
match 'users/:id' => 'users#destroy', :via => :delete, :as => :admin_destroy_user
get 'users#change_user_role'
end
Here I should submit the value of the checkbox in users_page to change_user_role and update the value in db and redirect it to users_page. How can I do that?

First of all, change your get method to put in your routes.rb because you'll be updating the resource in database:
Rails.application.routes.draw do
root to: 'pages#home'
get 'users/users_page'
devise_for :users
match 'users/:id' => 'users#destroy', :via => :delete, :as => :admin_destroy_user
// it will require user id in your url
resources :users do
member do
put :change_user_role
end
end
end
More on routes here
Then change your view to something like this:
<h1>Users</h1>
<% #users.each do |user| %>
<h5><%= user.email %></h5>
<%= form_for(user, url: change_user_role_user_path(user)) do |f| %>
<%= f.check_box(:admin) %>
<p><%= f.submit 'Submit Answer' %></p>
<% end %>
<br>
<%= link_to "Destroy", admin_destroy_user_path(user), method: :delete, data: { confirm: "You sure?" } %>
<% end %>
More on forms here
Your controller should look something like this:
class UsersController < ApplicationController
def users_page
#users = User.all
end
def change_user_role
#user = User.find(params[:id])
// if user is updated successfully then redirect
if(#user.update_attributes(user_params)
format.html { redirect_to users, notice: 'Role changed successfully' }
end
end
def destroy
#user = User.find(params[:id])
if #user.destroy
redirect_to root_url, notice: "User deleted."
end
end
// new method added to allow specific attributes only and discarding other malicious attributes that user may send
def user_params
params.require(:user).permit(:admin)
end
end
More on parameters here

Related

Redirect in destroy action not working properly

I am building a simple blog app using Ruby on Rails that allows users to log in/out, sign up and perform actions on their articles and profiles based on permissions and restrictions.
I have encountered a problem with the destroy User action. In the users/index view(where all existing users are listed), it causes no errors due to the url path containing no {:id}, but the redirect_to root_path does not work. If the same action is executed in the users/show page(personal profile page with some info and associated articles), due to the url being localhost/users/id, when the user is deleted I get "Couldn't find User with 'id'=33" error shown below. If I manually go to the root route, the successful account deletion message shows up and the action is performed correctly. So this is not a metter of DESTROY not working, but of redirection I believe. I have tried redirecting to different paths but it still doesn't work. Here are the related files:
routes.rb
Rails.application.routes.draw do
root "pages#home"
get "about", to: "pages#about"
resources :articles
get "signup", to: "users#new"
resources :users, except: [:new]
get 'login', to: 'sessions#new'
post 'login', to: 'sessions#create'
get 'logout' => :destroy, to: 'sessions#destroy'
end
pages_controller
class PagesController < ApplicationController
def home
redirect_to articles_path if logged_in?
end
def about
end
end
users_controller
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
before_action :require_user, only: [:edit, :update]
before_action :require_same_user, only: [:edit, :update, :destroy]
def index
#users = User.all
end
def show
#articles = #user.articles
end
def new
#user = User.new
end
def edit
end
def create
#user = User.new(user_params)
if(#user.save)
session[:user_id] = #user.id #logs user in automatically once they are signed up
flash[:notice] = "Welcome to AlphaBlog, #{#user.username}!"
redirect_to articles_path
else
render 'new'
end
end
def update
if #user.update(user_params)
flash[:notice] = "Account updated!"
redirect_to #user
else
render 'edit'
end
end
def destroy
#user.destroy
session[:user_id] = nil
flash[:notice] = "Account and all associated articles deleted!"
redirect_to root_path
end
private
def user_params
params.require(:user).permit(:username, :email, :password)
end
def set_user
#user = User.find(params[:id])
end
def require_same_user
if current_user != #user
flash[:alert] = "You can only edit your own profile!"
redirect_to current_user
end
end
end
sessions_controller
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
session[:user_id] = user.id
flash[:notice] = "Logged in successfully!"
redirect_to user
else
flash.now[:alert] = "There was something wrong with your login details!"
render 'new'
end
end
def destroy
session[:user_id] = nil
flash[:notice] = "Logged out."
redirect_to root_path
end
end
users/index.html.erb
<div class = "header">
<h1>
AlphaBlog
<% if logged_in? %>
<%= link_to 'Articles', articles_path, method: :get, class: "index-button-to" %>
<% else %>
<%= link_to 'Home', root_path(), method: :get, class: "index-button-to" %>
<%= link_to 'Articles', articles_path, method: :get, class: "index-button-to" %>
<% end %>
<%= render 'layouts/log_in_out_navigation'%>
</h1>
</div>
<h2>Alpha Bloggers</h2>
<div class="index-container">
<%# cycle through all articles and show them all in a table %>
<% #users.each do |user| %>
<div class = "index-article-container">
<div class="index-article-user" style = "color:rgb(16, 136, 255);">
<%= user.username %>
</div>
<div class="white">
<div class="index-article-title">
<%= gravatar_for(user, size: 150) %>
</div>
<div class="index-article-description">
<%# gives the plural word for multiple articles %>
<%= pluralize(user.articles.count, "article") %>
</div>
<div class="index-article-actions">
<%# shows selected article page %>
<%= link_to 'View Profile', user, class: "index-link-to show" %>
<% if logged_in? && current_user.username == user.username %>
<%# shows selected article EDIT page. edit_article_path because in routes,
the prefix for edit is edit_article && (article) because we need the id for the path as well%>
<%= link_to 'Edit Profile', edit_user_path(user), data: { turbo_method:
:get}, class: "index-link-to edit" %>
<%= link_to 'Delete Profile', user_path(current_user), data: {
turbo_method: :delete, turbo_confirm: "Are you sure? (This will also delete all of your
articles)" }, class: "index-link-to delete" %>
<% end %>
</div>
</div>
<div class="index-created-updated">
Joined <%= time_ago_in_words(user.created_at) %> ago.
</div>
</div>
<% end %>
users/show.html.erb
<div class = "header">
<h1>
AlphaBlog
<% if logged_in? %>
<%= link_to 'Articles', articles_path, method: :get, class: "index-button-to" %>
<%= link_to 'Bloggers', users_path, method: :get, class: "index-button-to" %>
<% else %>
<%= link_to 'Home', root_path(), method: :get, class: "index-button-to" %>
<%= link_to 'Articles', articles_path, method: :get, class: "index-button-to" %>
<%= link_to 'Bloggers', users_path, method: :get, class: "index-button-to" %>
<% end %>
<%= render 'layouts/log_in_out_navigation'%>
</h1>
</div>
<h2> <%= #user.username %>'s profile </h2>
<div class="show-users-image">
<%# gravatar_for method created in helpers/application_helper %>
<%= gravatar_for #user, size: 200 %>
<% if logged_in? && current_user.username == #user.username %>
<div class="index-profile-actions">
<%= link_to "Edit Profile", edit_user_path(#user), class: "index-link-to edit" %>
<%= link_to 'Delete Profile', user_path(current_user), data: { turbo_method: :delete,
turbo_confirm: "Are you sure? (This will also delete all of your articles)" }, class: "index-
link-
to delete", style: "margin-top:0.3vh" %>
</div>
<% end %>
</div>
<h3 style = "text-align:center">Articles</h3>
<%= render 'articles/article' %>
error page
The way to do this in Rails 7 is to update the destroy action in the UsersController by adding status: :see_other after the redirect, as follows:
def destroy
#user.destroy
session[:user_id] = nil
flash[:notice] = "Account and all associated articles deleted!"
redirect_to root_path, status: :see_other
end
I think the answer here is really a very different layout of your routes and controller (or to not reivent the wheel in the first place). Passing the user id through the parameters would be fine if your making a system where you are managing other users - but its pretty wonky when users are managing their own profiles.
For example this is how users CRUD their own profiles in a vanilla Devise setup:
Verb URI Pattern Controller#Action
------------------------------------------------------------------------
GET /users/cancel(.:format) devise/registrations#cancel
GET /users/sign_up(.:format) devise/registrations#new
GET /users/edit(.:format) devise/registrations#edit
PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
POST /users(.:format) devise/registrations#create
Note the lack of the :id parameter in the URI Pattern. Thats because its implied that the resource in question is the currently signed in user, and that the user is identified through the session (or a token).
The controller is named Registrations to avoid the ambiguity if the programmer later wants to add a UsersController to manage other users.
If you want to do something similiar you can generate singular routes by using the resource macro instead of resources.
# routes for user registration
resource :registrations,
only: [:new, :edit, :update, :create, :destroy]
# routes for viewing other users
resources :users, only: [:index, :show]
Which will generate:
Prefix Verb URI Pattern Controller#Action
-----------------------------------------------------------------------
new_registrations GET /registrations/new(.:format) registrations#new
edit_registrations GET /registrations/edit(.:format) registrations#edit
registrations GET /registrations(.:format) registrations#show
PATCH /registrations(.:format) registrations#update
PUT /registrations(.:format) registrations#update
DELETE /registrations(.:format) registrations#destroy
POST /registrations(.:format) registrations#create
Name it whatever you want. The core takeaway here is to not confuse two completely different problems - user management and user registrations and have separate endpoints and controllers for each responsibilty.
Then in your controller you simply authenticate the user from the session and redirect the user if they are not authenticated:
# Handles user account registration, updates and deleting accounts
class RegistrationsController < ApplicationController
before_action :require_user, except: [:new, :create]
# Displays the form for signing up a user
# GET /registrations
def new
#user = User.new
end
# Register a new user and sign them in
# POST /registrations
def create
#user = User.new(user_params)
if #user.save
reset_session # avoids session fixation attacks
session[:user_id] = #user.id #logs user in automatically once they are signed up
flash[:notice] = "Welcome to AlphaBlog, #{#user.username}!"
redirect_to articles_path
else
render :new
end
end
# Form for editing the users own profile
# GET /registrations/edit
def edit
#user = current_user
end
# Update the currently signed in user
# PATCH /registrations
def update
#user = current_user
if #user.update(user_params)
flash[:notice] = "Account updated!"
redirect_to current_user
else
render :new
end
end
# Cancel the current users registration
# DELETE /registrations
def delete
current_user.delete
reset_session # avoids session fixation attacks
flash[:notice] = "Account and all associated articles deleted!"
redirect_to root_path
end
private
def user_params
params.require(:user).permit(:username, :email, :password)
end
end
# Displays users
# Managing accounts is handled by RegistrationsController
class UsersController < ApplicationController
# GET /users
def index
#users = User.all
end
# GET /users/1
def show
#user = User.find(params[:id])
#articles = #user.articles
end
end
Since their is no id in the path you you need to set the delete button to send to the right path:
<%= button_to "Delete your account", registrations_path, method: :delete %>
And adjust your forms:
<%= form_with(model: #user, url: registrations_path) do |form| %>
# ...
<% end %>
Doing this the correct way would really be to do it the same way that Devise does and have a normal link that sends a GET request to a "Are you sure you want to delete your account?" page when then requires the user to enter their password or email and submits a DELETE request so that users don't accidentially delete their accounts.
But then again don't reinvent the authentication wheel unless you want a long and tedious lesson into wheelmaking.
I'm not sure you have truly got to the bottom of this. In your original approach I suspect two things are going on:
In users/index.html.erb you have link_to 'Delete Profile', user_path(current_user) but I think you want user_path(user). What you currently have will have every delete button try to delete the same user.
The fact that error says your are attempting to execute 'show' rather than 'destroy' makes me suspect that you do not have turbo loaded properly. You don't say what version of rails you are using, but for versions earlier than 7 you don't get turbo out of the box, and you should use UJS instead.
compare this https://guides.rubyonrails.org/getting_started.html#deleting-an-article with this https://guides.rubyonrails.org/v6.1/getting_started.html#deleting-an-article

using acts as followable gem on tweets

im trying to add acts a follower to my app so a user can follow other users and on the tweets index page only display the current users tweets and the tweets of the people they are following. i currently have a "follow" button on the user show page, but i would expect it to change into "following" on a click, but nothing changes. ive looked at other questions and documentation, but no luck. thank you.
Users show view:
<% if current_user.following?(#user) %>
<%= button_to "Following", {action: "unfollow", id: #user.id}, method: "post", class: "btn btn-secondary btn_unfollow", remote: true %>
<% else current_user != #user %>
<%= button_to "Follow", {action: "follow", id: #user.id}, method: "post", class: "btn btn-primary btn_follow", remote: true %>
<% end %>
Users Controller:
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#tweets = #user.tweets.order('created_at DESC')
authorize #user
end
def follow
#current_user.follow(#user)
#follow = Follow.find_by(follower: #current_user, followable: #user)
# #user = User.find(params[:id])
# current_user.follow(#user)
# current_user.follow(#user)
# redirect to user_path(#user)
# respond_to :js
end
def unfollow
#user = User.find(params[:id])
#current_user.stop_following(#user)
# current_user.stop_following(#user)
# redirect_to user_path(#user)
# respond_to :js
end
end
Routes:
resources :users do
member do
get :follow
get :unfollow
end
end
You're adding an ajax response by doing remote:true. You need to add a follow.js.erb and an unfollow.js.erb view that will re-render your partial.
Try and remove the remote: true part from your view:
<% if current_user.following?(#user) %>
<%= button_to "Following", {action: "unfollow", id: #user.id}, method: "post", class: "btn btn-secondary btn_unfollow" %>
<% elsif current_user != #user %>
<%= button_to "Follow", {action: "follow", id: #user.id}, method: "post", class: "btn btn-primary btn_follow" %>
<% end %>
Add post method for both follow and unfollow actions on routes.rb:
resources :users do
member do
post :follow
post :unfollow
end
end
and try current_user instead of #current_user in your UsersController if you're using Devise as a authentication solution:
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#tweets = #user.tweets.order('created_at DESC')
authorize #user
end
def follow
current_user.follow(#user)
#follow = Follow.find_by(follower: current_user, followable: #user)
# #user = User.find(params[:id])
# current_user.follow(#user)
# current_user.follow(#user)
# redirect to user_path(#user)
# respond_to :js
end
def unfollow
#user = User.find(params[:id])
current_user.stop_following(#user)
# current_user.stop_following(#user)
# redirect_to user_path(#user)
# respond_to :js
end
end

How to set "approved" user attribute to true with a button in Rails

I have a user model established by Devise and it has a Boolean attribute "approved" with default value set to false.
I created a separate controller called "newcomers" where I set index action to display all not approved users and update action to set "approved" to true
class NewcomersController < ApplicationController
def index
#users = User.where("approved = ?", false)
end
def update
#user = User.find(params[:id])
#user.update_attribute :approved, true
respond_to do |format|
format.html { redirect_to newcomers_path, notice: 'Member was successfully approved!' }
end
end
end
So, in my view I did
<h1>Members Requests</h1>
<% #users.each do |user| %>
<%= user.email %>
<%= form_for user, url: newcomers_path, method: :patch do |f| %>
<%= f.submit "Approve" %>
<% end %>
<% end %>
and in my routes I have resources :newcomers
So, I do not know how to make the button work the way it should. Meaning it should just update the attribute "approved" and set it to true. and return to the same page (index)
Try following code
<h1>Members Requests</h1>
<% #users.each do |user| %>
<%= user.email %>
<% if user.approved %>
<%= link_to 'Unapprove', newcomer_path(user, approve: false), method: :put %>
<% else %>
<%= link_to 'Approve', newcomer_path(user, approve: true ), method: :put %>
<% end %>
controller
def update
#user = User.find(params[:id])
#user.update_attribute :approved, params[:approve]
respond_to do |format|
format.html { redirect_to newcomers_path, notice: 'Member was successfully approved!' }
end
end
Just use a link_to in your view an point it to the update action in your controller:
<%= link_to 'Approve', newcomer_path(user_id), method: :put %>
In your controller just update the user with the given id an redirect to index path as you already do.
If you want it somewhat more fancy you can add a remote: true to your link_to and respond with an js to delete only the affected row from your view.
Make below changes
In view
<%= form_for user, url: newcomer_path(user, approved: true), method: :patch do |f| %>
<%= f.submit "Approve" %>
<% end %>
and in controller
def update
if params[:user].nil?
#user = User.find(params[:id])
#user.update_attribute :approved, true
respond_to do |format|
format.html { redirect_to newcomers_path, notice: 'Member was successfully approved!' }
end
end
end
let me know if it is not working...

Rails shows wrong forum path

I made Forum model which belongs to Category and in show view of every category each forum from that category needs to be showed, but links are pointing at wrong paths (for example, in category 4 I have only one forum which points to category/1/forum/1 and category 1 doesn't even exist).
One more note: each category has it's position field (integer) and they're sorted with that field in ascending order. Category 4 have position 1, but why would that number be on the place of category id in url?
When I try to access /category/4/forum/1 I get the error "Couldn't find Category with 'id'=1"
CategoriesController
class CategoriesController < ApplicationController
def index
categories_ordered
end
def new
#category = Category.new
categories_ordered
end
def create
#category = Category.new(category_params)
categories_ordered
if #category.save
redirect_to forums_path, notice: "Kategorija je uspešno kreirana."
else
render "new"
end
end
def show
find_category
find_forums
end
def edit
find_category
end
def update
find_category
if #category.update(category_params)
redirect_to category_path(#category), notice: "Kategorija je uspešno ažurirana."
else
render "edit"
end
end
def destroy
find_category
#category.destroy
redirect_to forums_path, notice: "Kategorija je uspešno obrisana."
end
private
def category_params
params.require(:category).permit(:name, :description, :position)
end
def find_category
#category = Category.find(params[:id])
end
def find_forums
#forums = #category.forums.all
end
def categories_ordered
#categories = Category.all.order("position ASC")
end
end
ForumsController
class ForumsController < ApplicationController
def new
find_category
#forum = #category.forums.new
end
def create
#category = Category.find(params[:category_id])
#forum = #category.forums.create(forum_params)
if #forum.save
redirect_to category_path(#category), notice: "Forum je uspešno kreiran."
else
render "new"
end
end
def show
find_category
find_forum
end
def edit
find_category
find_forum
end
def update
find_category
find_forum
if #forum.update(forum_params)
redirect_to forum_path(#forum), notice: "Forum je uspešno ažuriran."
else
render "edit"
end
end
private
def forum_params
params.require(:forum).permit(:title, :description)
end
def find_category
#category = Category.find(params[:category_id])
end
def find_forum
#forum = #category.forums.find(params[:id])
end
end
categories#show
<% authorize %>
<h2><%= #category.name %></h2>
<p><%= #category.description %></p>
<div class="list-group">
<% #category.forums.each do |f| %>
<a href="<%= forum_path(f) %>" class="list-group-item">
<h4 class="list-group-heading"><%= f.title %></h4>
<p class="list-group-text">
<%= f.description %>
</p>
</a>
<% end %>
</div>
<% if is_admin? %>
<%= link_to new_forum_path, class: "btn btn-primary" do %>
<span class="glyphicon glyphicon-plus"></span> Dodaj forum
<% end %>
<%= link_to edit_category_path(#category), class: "btn btn-primary" do %>
<span class="glyphicon glyphicon-pencil"></span> Izmeni
<% end %>
<%= link_to category_path(#category), class: "btn btn-danger", method: :delete, data: { confirm: "Da li ste sigurni da želite obrisati ovu kategoriju?" } do %>
<span class="glyphicon glyphicon-trash"></span> Obriši
<% end %>
<% end %>
routes.rb
Rails.application.routes.draw do
root "welcome#index"
get "start" => "welcome#index", as: "index"
get "registration" => "users#new", as: "register"
get "login" => "sessions#new", as: "login"
post "login" => "sessions#create"
get "logout" => "sessions#destroy", as: "logout"
get "users" => "users#index", as: "users"
post "users" => "users#create"
get "profile" => "users#show", as: "profile"
get "user/:id" => "users#show", as: "user"
get "user/:id/edit" => "users#edit", as: "edit_user"
patch "user/:id" => "users#update"
delete "user/:id" => "users#destroy"
get "categories/add" => "categories#new", as: "new_category"
get "category/:id" => "categories#show", as: "category"
patch "category/:id" => "categories#update"
delete "category/:id" => "categories#destroy"
get "category/:id/edit" => "categories#edit", as: "edit_category"
get "terms" => "welcome#terms", as: "terms"
get "wh" => "bugs#new", as: "wh"
get "bugs" => "bugs#index", as: "bugs"
post "bugs" => "bugs#create"
get "bug/:id" => "bugs#show", as: "bug"
delete "bug/:id" => "bugs#destroy"
get "forum" => "categories#index", as: "forums"
get "category/:category_id/forum/add" => "forums#new", as: "new_forum"
get "category/:category_id/forum/:id" => "forums#show", as: "forum"
get "category/:category_id/forum/:id/edit" => "forums#edit", as: "edit_forum"
patch "category/:category_id/forum/:id" => "forums#update"
delete "category/:category_id/forum/:id" => "forums#destroy"
resources :users
resources :sessions
resources :categories do
resources :forums
end
resources :bugs
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
Error is partially solved; I just had to use different parameters with ForumsController (category_id for categories and id for forums).
def find_category
#category = Category.find(params[:category_id])
end
def find_forum
#forum = #category.forum.find(params[:id])
end
And change forum routes accordingly.
It looks like problem still isn't solved. I changed this parts but I still have problems with URLs. Now category and forums IDs are mixed in url (instead of /category/4/forum/1 it shows /category/1/forum/4).
Edit: Problem is finally solved! This answer gave me an idea what I should do. I just had to specify #category with paths too (just changing two lines):
<div class="list-group">
<% #category.forums.each do |f| %>
<a href="<%= forum_path(#category, f) %>" class="list-group-item">
<h4 class="list-group-heading"><%= f.title %></h4>
<p class="list-group-text">
<%= f.description %>
</p>
</a>
<% end %>
</div>
<% if is_admin? %>
<%= link_to new_forum_path(#category), class: "btn btn-primary" do %>
<span class="glyphicon glyphicon-plus"></span> Dodaj forum
<% end %>

All posts get liked automatically upon login

I have some really strange situation right here. When I log in user all posts get liked by that user. Here are my routes:
resources :posts do
member do
put 'upvote', to: 'posts#upvote'
put 'unvote', to: 'posts#unvote'
end
end
Here is view:
<% if logged_in? %>
<% if post.liked_by current_user %>
<%= link_to "Dislike", unvote_post_path(post), class: 'vote', method: :put, remote: true, data: { toggle_text: 'Like', toggle_href: upvote_post_path(post), id: post.id } %>
<% else %>
<%= link_to "Like", upvote_post_path(post), class: 'vote', method: :put, remote: true, data: { toggle_text: 'Dislike', toggle_href: unvote_post_path(post), id: post.id } %>
<% end %>
<% end %>
and here is controller:
def upvote
#post = Post.find(params[:id])
#post.liked_by current_user
if request.xhr?
render json: { count: #post.get_likes.size, id: params[:id] }
else
redirect_to #post
end
end
def unvote
#post = Post.find(params[:id])
#post.unliked_by current_user
if request.xhr?
render json: { count: #post.get_likes.size, id: params[:id] }
else
redirect_to #post
end
end
I use gem https://github.com/ryanto/acts_as_votable and I added some ajax interaction following this: Like button Ajax in Ruby on Rails
The issue was in view if statement <% if post.liked_by current_user %> which made user like these posts instead of being boolean method. I switched it with <% if current_user.voted_for? post %> and added acts_as_voter to User model and it works fine now.

Resources