はじめに
現在オリジナルアプリの「散歩習慣化アプリ」製作中です。
その中でいいね機能を初めて実装したのでまとめます。
記事にすると長くなるので、①同期通信までと、②非同期通信で記事を分けてまとめます。
今回は①同期通信までをまとめます。
非同期通信については以下の記事でまとめてます。
『rails』いいね機能の実装方法② 非同期通信の実装
https://qiita.com/yuhi_taka/items/396305dae07ea2971313
実装の準備
まずは前提として以下のようなアプリを作成しています。
・散歩時間や感想、画像を投稿できるアプリ
・ホーム画面には投稿一覧が表示される
上記の散歩時間の下に
いいねボタンを表示させたい。
※参考文献 ここからは以下の記事を参考にしました
https://techtechmedia.com/favorite-function-rails/
モデルの設定
まずはモデルを作っていきます。
likesテーブルは、usersテーブルとwalksテーブルの外部キーをそれぞれ保持します。
従って以下のように記述して、rails db:migrateします。
t.integer :user_id
t.integer :walk_id
t.timestamps
これでlikesテーブルができました。
アソシエーションの設定
まずはuser.rbと、walk.rbにアソシエーションを設定します。
ユーザーは複数の「いいね」をする事ができ、
散歩記録も複数の「いいね」を保有できるので、has_manyを指定します。
has_many :likes
次にlike.rbに、usersテーブルと、walksテーブルへの関係を定義します。
それぞれ必ず紐づく先があるので、belongs_toを指定します。
belongs_to :user
belongs_to :walk
以上でアソシエーションの設定は終わりです。
viewにいいねを表示
次にviewに「いいね」を表示してみます。
条件としては
いいねが既に押されている場合には、「いいねを外す」ボタンを表示
いいねがまだ押されていない場合には、「いいね」ボタンを表示します。
省略
<h5 class="card-title">今日の一言:<%= walk.content%></h5>
<p class="card-text">散歩時間:<%= walk.time%>分</p>
<#以下いいね部分追加>
<% if user_signed_in? && current_user.liked_by?(walk.id) %>
いいねを外す
<% else %>
いいね
<% end %>
省略
この時にliked_by?(post.id)という自作メソッドで、いいねの有無を判断します。
liked_byメソッドの定義
次に先ほどviewで指定したliked_byメソッドを定義します。
テーブル操作に関するメソッドは、モデルに作成します。
def liked_by?(post_id)
likes.where(post_id: post_id).exists?
end
whereメソッドとexistsメソッドを使い、引数で渡したpost_idに紐づくlikeテーブルが存在するかを判定します。
もしも存在すればtrueを返し、存在しなかったらfalseを返します。
ここまでで以下のように散歩時間の下に「いいね」を配置しました。
※現状はまだリンクをつけてないので、ボタンは押せません。
ルーティングを設定する
さてここからは先程表示させたいいねボタンにリンクを付けたいと思います。
まずはルーティングの設定です。
いいねを付ける、削除するため、
likesに対してcreateとdestroyを定義します。
resources :walks do
resources :likes, only: [:create,:destroy]
end
注意点としては、walksテーブルにネストさせている事です。
ネストする理由は、どの散歩記録(walks)に対しての「いいね」かを特定する必要があるからです。
これでルーティングの設定ができました。
いいねボタンを押す
次にいいねにリンクを付けてlikesテーブルに保存できるようにします。
まずはコントローラーの設定からです。
likesコントローラーを生成します。
rails g controller likes
次にcreateアクションにいいねボタンを押下したときの処理を記述します。
def create
like = Like.create(user_id: current_user.id,walk_id: params[:walk_id] )
redirect_to root_path
end
これでlikesテーブルに保存ができるようになりました。
次にいいねボタンにリンクを付けます。
<h5 class="card-title">今日の一言:<%= walk.content%></h5>
<p class="card-text">散歩時間:<%= walk.time%>分</p>
<% if current_user.liked_by?(walk.id) %>
いいねを外す
<% else %>
<以下修正>
<%= link_to 'いいね', walk_likes_path(walk,walk.likes), method: :POST %>
<% end %>
ここでの注意点は、「walk_likes_path(walk,walk.likes)」で引数を2つ指定している点です。
ネストしているため、引数を2つ指定しないとno route machエラーが出ます。
試しにrails routesしてみます。
walk_likes POST /walks/:walk_id/likes(.:format) likes#create
「 /walks/:walk_id/likes(.:format) 」とあるように、walk_idと、walkに紐づくlikesもパスに含まれています。
ネストしている時は、引数を2つ指定するということに注意しましょう。
ここまでで、いいねボタンにリンクをつける事ができました。
いいねボタンの解除
次にいいねボタンの解除機能を実装します。
まずはコントローラーのdestroyアクションを追記します。
def destroy
Like.find_by(user_id: current_user.id,walk_id: params[:walk_id] ).destroy
redirect_to root_path
end
find_byメソッドは複数の条件をもとに検索できるメソッドです。
次にviewを修正します。
<h5 class="card-title">今日の一言:<%= walk.content%></h5>
<p class="card-text">散歩時間:<%= walk.time%>分</p>
<% if current_user.liked_by?(walk.id) %>
<以下修正>
<%= link_to 'いいねを外す', walk_likes_path(walk,walk.likes), method: :DELETE %>
<% else %>
<%= link_to 'いいね', walk_likes_path(walk,walk.likes), method: :POST %>
<% end %>
これで以下のように同期通信での、いいねが実装できました。
まとめ
今回はいいね機能について、同期通信までをまとめました。
次回は非同期通信処理についてまとめていきます。
非同期通信については以下の記事でまとめてます。
https://qiita.com/yuhi_taka/items/396305dae07ea2971313