丁寧すぎる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でゼロからアプリを作ってみたときにハマったところあれこれ