0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ツイートにスタンプでリアクションをする

Last updated at Posted at 2025-07-03

完成イメージ

スクリーンショット 2025-07-05 150903.png

1. Reactionモデルの作成

(すでに作成済みの場合はスキップ)

bash
rails generate model Reaction user:references tweet:references kind:string
rails db:migrate

2. モデルの関連付け・バリデーション

app/models/reaction.rb
class Reaction < ApplicationRecord
  belongs_to :user
  belongs_to :tweet

  # 1ユーザー1ツイートにつき各種類1つずつリアクションできる
  validates :user_id, uniqueness: { scope: [:tweet_id, :kind] }
  validates :kind, presence: true
end

3. DBインデックスの修正

bash
rails generate migration ChangeReactionIndex
db/migrate/xxxxxx_change_reaction_index.rb
class ChangeReactionIndex < ActiveRecord::Migration[8.0]
  def change
    remove_index :reactions, [:user_id, :tweet_id]
    add_index :reactions, [:user_id, :tweet_id, :kind], unique: true
  end
end

マイグレーションを実行

bash
rails db:migrate

4. モデルの関連付け(User/Tweet)

app/models/user.rb
class User < ApplicationRecord
  has_many :reactions, dependent: :destroy
end
app/models/tweet.rb
class Tweet < ApplicationRecord
  has_many :reactions, dependent: :destroy
end

5. ルーティングの追加

config/routes.rb
Rails.application.routes.draw do
  resources :tweets do
    resources :reactions, only: [:create, :destroy]
  end
  # ...他のルーティング...
end

6. コントローラーの作成・編集

app/controllers/reactions_controller.rb
class ReactionsController < ApplicationController
  before_action :authenticate_user!
  before_action :set_tweet

  def create
    reaction = current_user.reactions.find_or_initialize_by(tweet: @tweet, kind: params[:kind])
    if reaction.persisted?
      # すでに同じリアクションがあれば削除(トグル動作)
      reaction.destroy
      notice = 'リアクションを解除しました'
    else
      reaction.save
      notice = 'リアクションしました'
    end
    redirect_to tweets_path, notice: notice
  end

  def destroy
    reaction = current_user.reactions.find_by(tweet: @tweet, kind: params[:id])
    reaction&.destroy
    redirect_to tweets_path, notice: 'リアクションを解除しました'
  end

  private

  def set_tweet
    @tweet = Tweet.find(params[:tweet_id])
  end
end

7. ヘルパーの作成

app/helpers/reactions_helper.rb
module ReactionsHelper
  def reaction_kinds
    {
      "like" => "👍",
      "love" => "❤️",
      "laugh" => "😂"
    }
  end
end

8. ビューの編集

app/views/tweets/index.html.erb
<div class="reactions mt-2">
  <% reaction_kinds.each do |kind, emoji| %>
    <% user_reaction = tweet.reactions.find_by(user: current_user, kind: kind) if current_user %>
    <% count = tweet.reactions.where(kind: kind).count %>
    <%= form_with url: tweet_reactions_path(tweet), method: :post, local: true, class: 'd-inline' do |f| %>
      <%= hidden_field_tag :kind, kind %>
      <% if current_user && user_reaction %>
        <%= f.submit "#{emoji} #{count}(解除)", class: "btn btn-warning btn-sm" %>
      <% else %>
        <%= f.submit "#{emoji} #{count}", class: "btn btn-outline-secondary btn-sm" %>
      <% end %>
    <% end %>
  <% end %>
</div>

9. ヘルパーをコントローラーで使えるようにする

app/controllers/tweets_controller.rb
class TweetsController < ApplicationController
  helper ReactionsHelper
  # ...既存のコード...
end

10. サーバーを再起動

bash
rails s

11. 動作確認

  • ログインした状態でツイート一覧ページにアクセス
  • 各ツイート下に「👍」「❤️」「😂」のボタンが表示される
  • 各ボタンを押すと、その種類ごとにリアクションできる(同時に複数種類OK)
  • もう一度同じボタンを押すと解除できる
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?