LoginSignup
0
1

More than 1 year has passed since last update.

『rails』いいね機能の実装方法① 同期通信まで

Last updated at Posted at 2022-01-29

はじめに 

現在オリジナルアプリの「散歩習慣化アプリ」製作中です。
その中でいいね機能を初めて実装したのでまとめます。

記事にすると長くなるので、①同期通信までと、②非同期通信で記事を分けてまとめます。
今回は①同期通信までをまとめます。

非同期通信については以下の記事でまとめてます。
『rails』いいね機能の実装方法② 非同期通信の実装
https://qiita.com/yuhi_taka/items/396305dae07ea2971313

実装の準備

 まずは前提として以下のようなアプリを作成しています。
・散歩時間や感想、画像を投稿できるアプリ
・ホーム画面には投稿一覧が表示される
Image from Gyazo

上記の散歩時間の下に
いいねボタンを表示させたい。

データベース設計は以下のとおりです。
morning-walk.png

※参考文献 ここからは以下の記事を参考にしました
https://techtechmedia.com/favorite-function-rails/

モデルの設定

 まずはモデルを作っていきます。
likesテーブルは、usersテーブルとwalksテーブルの外部キーをそれぞれ保持します。
従って以下のように記述して、rails db:migrateします。

  t.integer :user_id
  t.integer :walk_id
  t.timestamps

これでlikesテーブルができました。

アソシエーションの設定

 次にアソシエーションの設定をします。
morning-walk.png

まずはuser.rbと、walk.rbにアソシエーションを設定します。

ユーザーは複数の「いいね」をする事ができ、
散歩記録も複数の「いいね」を保有できるので、has_manyを指定します。

user.rb,walk.rb
has_many :likes

次にlike.rbに、usersテーブルと、walksテーブルへの関係を定義します。
それぞれ必ず紐づく先があるので、belongs_toを指定します。

like.rb
  belongs_to :user
  belongs_to :walk

以上でアソシエーションの設定は終わりです。

viewにいいねを表示

 次にviewに「いいね」を表示してみます。
条件としては
いいねが既に押されている場合には、「いいねを外す」ボタンを表示
いいねがまだ押されていない場合には、「いいね」ボタンを表示します。

index.html
省略
   <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メソッドを定義します。
テーブル操作に関するメソッドは、モデルに作成します。

user.rb
 def liked_by?(post_id)
    likes.where(post_id: post_id).exists?
 end

whereメソッドとexistsメソッドを使い、引数で渡したpost_idに紐づくlikeテーブルが存在するかを判定します。
もしも存在すればtrueを返し、存在しなかったらfalseを返します。

ここまでで以下のように散歩時間の下に「いいね」を配置しました。
Image from Gyazo
※現状はまだリンクをつけてないので、ボタンは押せません。

ルーティングを設定する

 さてここからは先程表示させたいいねボタンにリンクを付けたいと思います。
まずはルーティングの設定です。
いいねを付ける、削除するため、
likesに対してcreateとdestroyを定義します。

routes.rb
 resources :walks do
    resources :likes, only: [:create,:destroy]
  end

注意点としては、walksテーブルにネストさせている事です。
ネストする理由は、どの散歩記録(walks)に対しての「いいね」かを特定する必要があるからです。

これでルーティングの設定ができました。

いいねボタンを押す

 次にいいねにリンクを付けてlikesテーブルに保存できるようにします。
まずはコントローラーの設定からです。
likesコントローラーを生成します。

rails g controller likes

次にcreateアクションにいいねボタンを押下したときの処理を記述します。

likes_controller.rb
def create
    like = Like.create(user_id: current_user.id,walk_id: params[:walk_id] )
    redirect_to root_path
  end

これでlikesテーブルに保存ができるようになりました。

次にいいねボタンにリンクを付けます。

index.html
<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アクションを追記します。

likes_controller.rb
def destroy
    Like.find_by(user_id: current_user.id,walk_id: params[:walk_id] ).destroy
    redirect_to root_path
  end

find_byメソッドは複数の条件をもとに検索できるメソッドです。

次にviewを修正します。

index.html
<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 %>

これで以下のように同期通信での、いいねが実装できました。

Image from Gyazo

まとめ

 今回はいいね機能について、同期通信までをまとめました。
次回は非同期通信処理についてまとめていきます。

非同期通信については以下の記事でまとめてます。
https://qiita.com/yuhi_taka/items/396305dae07ea2971313

参考文献
https://techtechmedia.com/favorite-function-rails/

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1