[RUBY] [Rails] Favorite feature

What you want to implement

-Only reviewers can register as favorites --Implemented favorite function with Ajax communication --Display your favorites list on My Page

table of contents

  1. Create a favorite table
  2. Association
  3. Routing
  4. Controller
  5. View

1. Create a favorite table

Create a favorite table to store which posts and who did your favorites.

Terminal
rails g model like

db/migrate/20XXXXXXXXXXXX_create_likes.rb


class CreateLikes < ActiveRecord::Migration[6.0]
  def change
    create_table :likes do |t|
      t.references :user, null: false, foreign_key: true
      t.references :post, null: false, foreign_key: true
      t.timestamps
      t.index [:user_id, :post_id], unique: true   #Preventing the same user from liking the same post
    end
  end
end

2. Association

Use the ** dependent:: destroy option ** to ensure that your favorites are deleted when the post is deleted. Describe in the parent model.

app/models/likei.rb


class Like < ApplicationRecord
  belongs_to :user
  belongs_to :post
end

app/models/post.rb


class Post < ApplicationRecord
  belongs_to :user
  has_many :likes, dependent: :destroy
  has_one_attached :image
  ~Abbreviation~
end

app/models/user.rb


class User < ApplicationRecord
 ~Abbreviation~
  has_many :posts
  has_many :likes
  has_one_attached :image
end

3. Routing

We use routing nesting because we need to indicate which post we like. I wish I could register and delete my favorites, so set the "create action" and "destroy action".

ruby:config.routes.rb


Rails.application.routes.draw do
  devise_for :users
  root 'posts#top'
  resources :posts do
    collection do
      get 'top'
    end
    resources :likes, only: [:create, :destroy]
  end
  resources :users, only: [:show]
end

4. Controller

Define "create action" and "destroy action" in the controller. Favorites can be registered by anyone other than the poster.

app/controllers/likes_controller.rb


class LikesController < ApplicationController
  def create
    @post = Post.find(params[:post_id])
    if @post.user_id != current_user.id   #You can register favorites other than your own posts
      @like = Like.create(user_id: current_user.id, post_id: @post.id)
    end
  end
  def destroy
    @post = Post.find(params[:post_id])
    @like = Like.find_by(user_id: current_user.id, post_id: @post.id)
    @like.destroy
  end
end

The posts that the user has registered as favorites are displayed on My Page. Find the logged-in user's favorites from the Likes table, sort them in descending order, and retrieve the post_ids in an array. The data is stored in @likes by the find method.

app/controllers/users_controller.rb


class UsersController < ApplicationController
  def show
    @user = User.find(params[:id])
    birthday = @user.birthday
    date_format = "%Y%m%d"
    @age = (Date.today.strftime(date_format).to_i - birthday.strftime(date_format).to_i) / 10000
    @posts = @user.posts.order(created_at: :desc)

    likes = Like.where(user_id: current_user.id).order(created_at: :desc).pluck(:post_id)
    @likes = Post.find(likes)
  end
end

5. View

Create a partial template to display the part where the favorite button is displayed. It branches depending on whether it is registered as a favorite in the if statement or not.

ruby:app/views/posts/show.html.erb


~Abbreviation~
<div class='star-btn' id="like_<%= @post.id %>">
  <%= render "likes/like", post: @post %>
</div>
~Abbreviation~

ruby:app/views/likes/_like.html.erb


<% if !Like.exists?(user_id: current_user.id, post_id: post.id) %>
  <%= link_to post_likes_path(post.id), method: :post, remote: true, class:"like-btn" do %>
    <i class="fas fa-star star-icon1"></i>
  <% end %>
  <span class="star-count1"><%= post.likes.count %></span>
<% else %>
  <%= link_to post_like_path(post_id: post.id, id: post.likes[0].id), method: :delete, remote: true, class:"like-btn" do %>
    <i class="fas fa-star star-icon2"></i>
  <% end %>
  <span class="star-count2"><%= post.likes.count %></span>
<% end %>

When the favorite button is clicked, the "create action" or "destroy action" is executed, the partial template is updated by Ajax communication, and the favorite button is displayed.

ruby:app/views/likes/create.js.erb


$('#like_<%= @post.id %>').html("<%= j(render partial: 'likes/like', locals: { post: @post }) %>");

ruby:app/views/likes/destroy.js.erb


$('#like_<%= @post.id %>').html("<%= j(render partial: 'likes/like', locals: { post: @post }) %>");

The favorite list of My Page is displayed using the each statement.

ruby:app/views/users/show.html.erb


<% if @likes.present? %>
    <ul class="relative-post-lists">
    <% @likes.each do |like| %>
      <li class='post-list'>
        <%= link_to post_path(like.id) do %>
        <div class='post-img-content'>
          <%= image_tag like.image, class: "post-img" %>
        </div>
          <div class='relative-post-name'>
Product name:<%= like.name %>
          </div>
          <div class='relative-item-price'>
            <span><%= like.price %>Circle(tax included)</span>
          </div>
          <div class="relative-post-evaluation">
            <span>Evaluation:</span>
              <span id="star-rate-<%= like.id %>"></span>
              <script>
                $('#star-rate-<%= like.id %>').raty({
                  size: 36,
                  starOff: "<%= asset_path('star-off.png') %>",
                  starOn: "<%= asset_path('star-on.png') %>",
                  starHalf: "<%= asset_path('star-half.png') %>",
                  half: true,
                  readOnly: true,
                  score: <%= like.evaluation %>,
                });
              </script>
              <%= like.evaluation %>
          </div>
          <div class='user-img-content'>
            <%= image_tag like.user.image ,class:"mini-img" if like.user.image.attached? %>
            <%= link_to like.user.nickname, user_path(like.user.id) %>
          </div>
          <div class="relative-post-date">
Updated date:<%= like.created_at.strftime("%Y.%m.%d") %>
          </div>
        <% end %>
      </li>
    <% end %>
    </ul>
  <% end %>

Reference link

https://qiita.com/manbolila/items/43a04e8d0d5018cf7f62 https://qiita.com/naberina/items/c6b5c8d7756cb882fb20 https://qiita.com/naota7118/items/e009eff939b5a764672d

Recommended Posts

[Rails] Favorite feature
Replace Rails favorite feature (Ajax) from jQuery to plain JavaScript
First pagination feature added in rails
[Rails g.error]
Rails basics
Rails Review 1
Rails API
Rails migration
[Rails] first_or_initialize
rails tutorial
About Rails 6
Rails foundation
Rails memorandum
rails tutorial
rails tutorial
rails tutorial
[Rails] devise
rails tutorial
rails tutorial
Rails Tips
rails method
rails tutorial
[Rails] ActiveRecord
[Rails] form_with
Rails Review 2
How to implement a like feature in Rails
Implement the Like feature in Ajax with Rails.