Railsアプリでお気に入り機能を実装したい!
はじめに
現在railsでアプリを作成していてお気に入り機能を実装しました。
その備忘録としてアウトプットしたいと思います!
前提
- Deviseでユーザー管理機能を実装済み
- ユーザーに紐づくモデルを作成済み(tweetモデルやarticleモデルなど)
- テンプレートエンジンはhamlを採用
開発環境
OS: macOS Catalina
データベース: Mysql
バックエンド: Ruby on Rails 6.0
テキストエディタ: Visual Studio Code
目次
1.データベース設計
2.ルーティングの記述
3.アソシエーションの記述
4.コントローラーの記述
5.Viewの記述
1. データベース設計
さきにER図を御覧ください。
今回はUserテーブル、Eventテーブル、Favoriteテーブルで考えたいと思います。
Eventテーブルとそのカラムについては任意の設定で大丈夫です。
FavoriteテーブルはUserテーブルとEventテーブルの中間テーブルとなります。
そのため、カラムにはuser_idとevent_idを持たせます。
これで、どのユーザーがどのイベントをお気に入りしたかをデータベースに保存できます。
それでは、この設計に沿って準備をしていきます!
下準備
$rails g model Favorite user_id:integer tweet_id:integer
$rails g controller favorites create destroy
$rails db:migrate #忘れずに
マイグレーションファイルはこんな感じ!
2. ルーティングの記述
#=====================================
root 'events#index'
devise_for :users
resources :events do
resource :favorites, only: [:create, :destroy]
end
#======================================
ポイントは2つです
favoritesアクションはeventアクションにネストさせる
こうすることで、お気に入りされたイベントの情報を引き出すのが楽になりますfavoritesアクションはresorcesではなくresorceを用いる
favoriteはユーザーみたいに詳細ページや編集ページがいらないので個別のidはいりません。
なので省略するためにresorce
を用います
3. アソシエーションの記述
favoriteはuserとeventに属する側なのでbelongs_to
で記述します
class Favorite < ApplicationRecord
belongs_to :user
belongs_to :event
end
userとeventモデルは以下のように記述します
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :tweets
has_many :favorites
has_many :favorite_events, through: :favorites, source: :event
end
class Event < ApplicationRecord
belongs_to :user
has_many :favorites
end
User.rbに関して
source
source
は「参照元のモデル」をさすオプションです。
これを指定することでアソシエーションでメソッドチェーンする時の名称を変更することができます。
本当はhas_many :events, through: :favorites
と記述したいのですが、上のhas_many :eventsと重複してしまうため、favorite_eventsと名称を変更しています。
has many throughを使った「ユーザーがファボしたイベントの表示」
これで、@user.favorite_events
とやることで、「ユーザーがファボしたイベント」を取得することができるようになります。
更に、お気に入り機能は登録だけでなく解除の機能も必要です。
そのため、Eventモデルに「このイベントをユーザーがファボしているかどうか」を判定するメソッドを用意します。
ユーザーがイベントをお気に入りしたかどうかの判定メソッド
class Event < ApplicationRecord
belongs_to :user
has_many :favorites
# 追加
def already_favorited?(user) #引数を受け取るように設定
favorites.where(user_id: user.id).exists?
end
end
普通メソッドはコントローラーの中に記述していくと思います。
僕自身、モデルにはアソシエーションやバリデーションだけを書く場所だと認識していましたがメソッドも定義することができます。
余談ですが、このようにモデルに定義するメソッドをインスタンスメソッドと呼びます。
インスタンスメソッドはクラスで生成されたインスタンスにメソッドを設定できます。
例えば、events_controller.rb
が下記の場合を見てみましょう
def show
@event = Event.find(params[:id])
end
この場合の@event
がEventクラスで生成されたインスタンスにあたります。
この後のViewのセクションでも登場しますが@event.already_favorited?(current_user)
と記述することで、現在ログインしているユーザーが対象のeventをお気に入りしているかどうかの判定をすることができるようになります!
4. コントローラーの記述
UsersControllerの記述
class UsersController < ApplicationController
def index
@users = User.all
end
def show
@user = User.find(params[:id])
@events = @user.events
@favorite_events = @user.favorite_events
end
end
@favorite_events = @user.favorite_events
と記述することで
Viewでeachメソッド
を使用することで「ユーザーがファボしたイベント」を取得することができます。
FavoritesControllerの記述
class FavoritesController < ApplicationController
def create
favorite = current_user.favorites.build(event_id: params[:event_id])
favorite.save
redirect_back(fallback_location: root_path)
end
def destroy
favorite = Favorite.find_by(event_id: params[:event_id], user_id: current_user.id)
favorite.destroy
redirect_back(fallback_location: root_path)
end
end
createアクション
アソシエーションを組んでいるので、current_user.favorites
とすることでfavoriesテーブルのuser_idにcurrent_user.idを入れることができます。あとはevent_idを入れるのですが、、、
ポイントはbuild
です。newでもcreateでも問題ないですが、インスタンスに紐づくインスタンスを生成するときにbuildが形式的に使われるのでこのように記述します。
createは自動的にsaveまで行いますが、buildはnewと同じく生成するだけなのでfavorite.save
を記述してあげます。
redirect_back
いいね、もしくはいいねを解除したときに同じページのままでいてほしいのでこのように記述します。
redirect_backで戻るべきページがなくてエラーがおきてしまう可能性があるので(fallback_location: root_path)
と記述してエラーになるのを防ぎます。
destroyアクション
特になしです笑
redirect_backに関してはcreateアクションと同じくいいねを解除した後も同じページに遷移するように記述しておきます。
5. Viewの記述
冒頭の通りHTMLではなくhamlで記述します。
お気に入りボタンの実装
- if @event.already_favorited?(current_user)
%p.favorite-heading
保存をキャンセル
= link_to event_favorites_path(@event), method: :delete, class: "favorite-link" do
= icon("fas", "star", class: "favorite-icon")
- else
%p.favorite-heading
イベントを保存
= link_to event_favorites_path(@event), method: :post, class: "favorite-link" do
= icon("far", "star", class: "favorite-icon")
解説
- - if @event.already_favorited?(current_user)
user.rbに定義したalready_favorited?(user)
メソッドをViewで使用します。
引数としてcurrent_userを渡すことで、現在ログインしているユーザーが対象イベントをファボしているかどうかの条件分岐をしています。
もし、すでにファボしている場合はdestroyアクション
をファボしていなければcreateアクション
を実行します。
- = link_to~
pathはrails routes
で確認してタイプミスがないように気をつけましょう。
メソッドもしっかり記述しましょう。
地味ですが、最後のdo
は意外と躓いたポイントです。今回はアイコンを押してファボしたいので要素全体をリンクにするためにこのように記述します。
アイコンはFont Awesomeでスターを使用します。
Font Awesomeの導入の仕方はこちらをご覧ください
以上で実装はおわりです!!
おわりに
最後まで読んでいただきありがとうございました!
改良点としては、いいねを非同期通信にできたらもうすこしUI/UXの点でよくなると思います。
お疲れさまでした。。
参考文献
Author And Source
この問題について(Railsアプリでお気に入り機能を実装したい!), 我々は、より多くの情報をここで見つけました https://qiita.com/anago1030/items/6e3a1dced80296810f26著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .