Hotwire: Rails: ライクボタンの習作
下記のツイートを参考にした Hotwire の習作です。
likes のルーティングは todos 配下に変更しました。
ビューはスキャフォールドをベースにしています。
今回の例では Turbo Flames を使わないため _like.html.erb のタグは turbo_frame_tag から div に変更しました。
current_user はユーザ1固定です。
完成画面
環境
ruby 3.1.2
Rails 7.0.3
実装
rails new hw_like_button && cd hw_like_button
bin/rails g model User name
bin/rails g scaffold Todo description
bin/rails g model Like description user:belongs_to todo:belongs_to
bin/rails db:migrate
ユーザ2名とTodo3件を用意する。
ユーザ1はTodo2をライクしている。
ユーザ2はTodo3をライクしている。
# users.yml
user_1:
name: user_1
user_2:
name: user_2
# todos.yml
todo_1:
description: todo_1
todo_2:
description: todo_2
todo_3:
description: todo_3
# likes.yml
user_1_likes_todo_2:
user: user_1
todo: todo_2
user_2_likes_todo_3:
user: user_2
todo: todo_3
bin/rails db:fixtures:load
Rails.application.routes.draw do
resources :todos do
resources :likes, only: %i[ create destroy ]
end
root "todos#index"
end
class Todo
has_many :likes
end
class TodosController < ApplicationController
# ...
def index
@todos = Todo.all.order(:description)
end
# ...
end
class ApplicationController < ActionController::Base
helper_method :current_user
def current_user
@current_user ||= User.find_by(name: "user_1")
end
end
bin/rails generate controller likes --skip-routes
rm app/helpers/likes_helper.rb
rm test/controllers/likes_controller_test.rb
touch app/views/likes/_like.html.erb
<%= tag.div id: dom_id(todo, :like) do %>
<% if like&.persisted? %>
<%= button_to "Unlike", todo_like_path(todo, like), method: :delete %>
<% else %>
<%= button_to "👍 Like", todo_likes_path(todo), method: :post %>
<% end %>
<% end %>
app/views/todos/_todo.html.erb
<div id="<%= dom_id todo %>">
<p><%= todo.description %></p>
<%= render partial: "likes/like", locals: { todo: todo, like: todo.likes.find_by(user: current_user) } %>
<%= tag.div(todo.likes.count, id: dom_id(todo, :likes_count)) %>
</div>
<hr>
bin/rails s
この時点で Todoに Like/Unlike ボタンとライク数が表示される。
続けてアクションを実装する。
class LikesController < ApplicationController
before_action :set_todo
def create
@like = @todo.likes.where(user: current_user).first_or_create
end
def destroy
@like = Like.find(params[:id])&.destroy
render :create
end
private
def set_todo
@todo = Todo.find(params[:todo_id])
end
end
touch app/views/likes/create.turbo_stream.erb
"likes/like" を replace する。
dom_id(@todo, :likes_count) の中身ライク数を update する。
<%= turbo_stream.replace(dom_id(@todo, :like), partial: "likes/like", locals: { todo: @todo, like: @like} ) %>
<%= turbo_stream.update(dom_id(@todo, :likes_count), @todo.likes.count) %>
以上です。
この記事が気に入ったらサポートをしてみませんか?