1. モデルの作成と関連付け
1.1 Bookmarkモデルの作成
rails generate model Bookmark user:references tweet:references
rails db:migrate
1.2 モデル間の関連付けの設定
app/models/bookmark.rb
class Bookmark < ApplicationRecord
belongs_to :user
belongs_to :tweet
# 同じユーザーが同じツイートを複数回ブックマークできないようにする
validates :user_id, uniqueness: { scope: :tweet_id }
end
app/models/user.rb
class User < ApplicationRecord
# 既存の関連付けに追加
has_many :bookmarks, dependent: :destroy
has_many :bookmarked_tweets, through: :bookmarks, source: :tweet
end
app/models/tweets.rb
class Tweet < ApplicationRecord
# 既存の関連付けに追加
has_many :bookmarks, dependent: :destroy
has_many :bookmarked_by_users, through: :bookmarks, source: :user
end
2. ルーティングの設定
Rails.application.routes.draw do
# 既存のルーティングに追加
resources :tweets do
member do
post 'bookmark'
delete 'unbookmark'
end
end
# ブックマーク一覧用のルート
get 'bookmarks', to: 'bookmarks#index'
end
3. コントローラーの実装
3.1 BookmarksControllerの作成
rails generate controller Bookmarks index
app/controllersapp/controllers/bookmarks_controller.rb
class BookmarksController < ApplicationController
before_action :authenticate_user!
def index
@bookmarked_tweets = current_user.bookmarked_tweets.includes(:user).order(created_at: :desc)
end
end
3.2 TweetsControllerにブックマーク関連のアクションを追加
app/controllersapp/controllers/Tweets_controller.rb
class TweetsController < ApplicationController
# 既存のアクションに追加
def bookmark
@tweet = Tweet.find(params[:id])
current_user.bookmarks.create(tweet: @tweet)
respond_to do |format|
format.html { redirect_to @tweet }
format.turbo_stream
end
end
def unbookmark
@tweet = Tweet.find(params[:id])
current_user.bookmarks.find_by(tweet: @tweet).destroy
respond_to do |format|
format.html { redirect_to @tweet }
format.turbo_stream
end
end
end
4. ビューの実装
4.1 ブックマークボタンのパーシャル作成
app/views/tweets/_bookmark_button.html.erb:
<% if current_user&.bookmarked?(@tweet) %>
<%= button_to tweet_unbookmark_path(@tweet),
method: :delete,
class: "bookmark-button bookmarked",
form: { data: { turbo: true } } do %>
<i class="fas fa-bookmark"></i>
<% end %>
<% else %>
<%= button_to tweet_bookmark_path(@tweet),
method: :post,
class: "bookmark-button",
form: { data: { turbo: true } } do %>
<i class="far fa-bookmark"></i>
<% end %>
<% end %>
4.2 ブックマーク一覧ページの作成
app/views/bookmarkers/index.html.erb:
<div class="container">
<h1>ブックマーク一覧</h1>
<div class="tweets-list">
<%= render partial: "tweets/tweet", collection: @bookmarked_tweets %>
</div>
</div>
4.3 Turbo Streamテンプレートの作成
app/views/tweets/bookmark.turbo_stream.erb:
<%= turbo_stream.replace "bookmark_button_#{@tweet.id}" do %>
<%= render "tweets/bookmark_button", tweet: @tweet %>
<% end %>
app/views/tweets/unbookmark.turbo_stream.erb:
<%= turbo_stream.replace "bookmark_button_#{@tweet.id}" do %>
<%= render "tweets/bookmark_button", tweet: @tweet %>
<% end %>
5. スタイルの追加(しなくてもいい)
.bookmark-button {
background: none;
border: none;
cursor: pointer;
padding: 5px;
i {
font-size: 1.2rem;
color: #657786;
}
&.bookmarked i {
color: #1DA1F2;
}
&:hover i {
color: #1DA1F2;
}
}
6. ヘルパーメソッドの追加
app/helpers/tweets_helper.rb
module TweetsHelper
def bookmarked?(tweet)
current_user&.bookmarked_tweets&.include?(tweet)
end
end
注意点
・ユーザー認証(Devise)が実装されていることを前提としている
・Font Awesomeなどのアイコンライブラリが必要
・Turbo/Hotwireが有効になっていることを確認
・必要に応じて適切なエラーハンドリングを追加
・この実装により、以下の機能が提供される:
ツイートのブックマーク追加/削除
ブックマーク一覧の表示
非同期でのブックマーク状態の更新
ユーザーごとのブックマーク管理