うさぎのイラスト

ネットアンサー55備忘録

web技術を書いていきます

丁寧すぎるRails『アソシエーション』チュートリアル① で学んだこと

-2023年01月31日-
本記事はqiita:【初心者向け】丁寧すぎるRails『アソシエーション』チュートリアル【幾ら何でも】【完璧にわかる】より、学んだ箇所を何点かピックアップしていきます。

本記事は「 UserとTweetの実装(1対多) 」「Favoriteの実装(多対多)」を中心として記述します。

【アソシエーション①:UserとTweetの関係(1対多)】

・User側から見てTweetは多数投稿することが出来ます。
・Tweet側から見たら、Userは一人しかおりません。
# user.rb
  has_many :tweets
# tweet.rb
  belongs_to :user

【アソシエーション②:Favoriteの実装(多対多)】

・User側から見て複数のTweetに「いいね(Favorite)」することが出来ます。
・Tweet側から見たら複数のUserが「いいね」することが出来ます。
※UserとTweetを繋げるための中間テーブル(Favorite)を作成します。
# favorite.rb
class Favorite < ApplicationRecord
    belongs_to :user
    belongs_to :tweet
end
# user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  has_many :tweets
  has_many :favorites  # 追加
end
# tweet.rb
class Tweet < ApplicationRecord
    belongs_to :user
    has_many :favorites  # 追加
end

Favorite機能の仕組みについて

一人のUserは各Tweetに対して、一回っきりのFavoriteしかできません。ですので、ここはtoggleのような仕組みが必要になってきます。
# tweet.rb
    def favorited_by?(user)
        favorites.where(user_id: user.id).exists?
    end
# tweets/index.html.erb
  <% if user_signed_in? %>
    <% if tweet.favorited_by?(current_user) %> <!-- ログインしているユーザーがFavoriteしたかどうかで分岐 -->
        <p><span>お気に入り解除: </span><%=button_to tweet.favorites.count, tweet_favorites_path(tweet.id), method: :delete %></p>
    <% else %>
        <p><span>お気に入り登録: </span><%=button_to tweet.favorites.count, tweet_favorites_path(tweet.id), method: :post %></p>
    <% end %>
  <% else %>
    <p><span>お気に入り数: </span><%= tweet.favorites.count %></p>
  <% end %>

Userが「いいね」したTweet記事一覧を見る方法

# user.rb
  has_many :favorite_tweets, through: :favorites, source: :tweet  # 追加
「through」経由します、今回はfavoritesテーブルを経由しますので、favorites
「source」は参照元のモデルを表します、今回はtweetのモデルを参照したいので、tweet
# app/controllers/users_controller.rb
  def show
    @user = User.find(params[:id])
    @tweets = @user.tweets
    @favorite_tweets = @user.favorite_tweets # 追加
  end
userのコントローラーで上記のように設定をすることが出来ます。これでuserのhtmlにこのuserが「お気に入り」をした「tweet一覧」が表示できます。

ログアウト機能の不具合調整

ログアウトするために、deleteをformから投げなければならず、link_toからのアンカーからではどうしてもエラーとなってしまうために、button_toに変更して、form型のhtmlにして解決しました。
# app/views/layouts/application.html.erb
# 【修正前】
<%= link_to "ログアウト", destroy_user_session_path, method: :delete %>
# app/views/layouts/application.html.erb
# 【修正後】
<%= button_to "ログアウト", destroy_user_session_path, method: :delete %>
※下記でlink_toのままでも解決する記事を見つけたが、今度検討してみる。
Rails7のlink_toでmethod: :deleteする
Rails 7.0 + Ruby 3.1でゼロからアプリを作ってみたときにハマったところあれこれ