ブックマーク機能

## 1. モデルの作成と関連付け
### 1.1 Bookmarkモデルの作成
```ruby:bush

rails generate model Bookmark user:references tweet:references
rails db:migrate
```
### 1.2 モデル間の関連付けの設定
app/models/bookmark.rb
```ruby:bookmark.rb
class Bookmark < ApplicationRecord
  belongs_to :user
  belongs_to :tweet
  
  # 同じユーザーが同じツイートを複数回ブックマークできないようにする
  validates :user_id, uniqueness: { scope: :tweet_id }
end
```
app/models/user.rb
```ruby:user.rb
class User < ApplicationRecord
  # 既存の関連付けに追加
  has_many :bookmarks, dependent: :destroy
  has_many :bookmarked_tweets, through: :bookmarks, source: :tweet
end
```
app/models/tweets.rb
```ruby:tweets.rb
class Tweet < ApplicationRecord
  # 既存の関連付けに追加
  has_many :bookmarks, dependent: :destroy
  has_many :bookmarked_by_users, through: :bookmarks, source: :user
end
```
## 2. ルーティングの設定
```ruby:routes.rb
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の作成
```ruby:bush
rails generate controller Bookmarks index
```
app/controllersapp/controllers/bookmarks_controller.rb
```ruby: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
```ruby: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:
```ruby:_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:
```ruby: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:
```ruby: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:
```ruby:unbookmark.turbo_stream.erb
<%= turbo_stream.replace "bookmark_button_#{@tweet.id}" do %>
  <%= render "tweets/bookmark_button", tweet: @tweet %>
<% end %>
```
## 5. スタイルの追加(しなくてもいい)
```ruby:scss
.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
```ruby:tweets_helper.rb
module TweetsHelper
  def bookmarked?(tweet)
    current_user&.bookmarked_tweets&.include?(tweet)
  end
end
```
注意点
・ユーザー認証（Devise）が実装されていることを前提としている
・Font Awesomeなどのアイコンライブラリが必要
・Turbo/Hotwireが有効になっていることを確認
・必要に応じて適切なエラーハンドリングを追加
・この実装により、以下の機能が提供される：
ツイートのブックマーク追加/削除
ブックマーク一覧の表示
非同期でのブックマーク状態の更新
ユーザーごとのブックマーク管理