いいね機能(非同期通信)

1. 序論
Rails初心者が詰まりやすい非同期通信を用いたいいね機能の追加方法をまとめました。

2. 環境
Rails 6.1.7
deviceによるuserモデルと本を投稿するbookモデルが存在するサンプルアプリを使用

3. モデル作成
以下のコマンドでfavoritesモデルを作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3157044/295dee8f-03e8-7676-158d-8b9abf48894a.png)

今回、favoritesモデルはuserモデルとbookモデルの中間テーブルなので、マイグレーションファイルに外部キーを記述し、rails db:migrateを行う。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3157044/600e3d0f-b30e-b078-00ac-f15319174d7b.png)


各モデルにhas_manyとbelongs_toの記述を追加する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3157044/b6ff214f-dc36-d8c9-a139-15399ea24f54.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3157044/2a5c1023-41af-0aca-9fa4-5491d4586db8.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3157044/f6ba0346-1840-e5f9-32ff-124d601f45d0.png)

4.ルーティングの設定
今回は投稿された本に対してのいいね機能ですので、resource booksにネストさせます。さらに、いいねをするか外すかだけですので
createとdestroyのみ記述します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3157044/0e4fb23b-9111-e9f4-0a69-1b2bb126b290.png)

記述後、rails routesでpathやurlを確認しておきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3157044/1a2845e1-ffa8-204d-4179-b4effd92ab91.png)



5.コントローラ

まずは、以下のコマンドでコントローラを作成します。今回はviewファイルは必要ないのでシンプルなコマンドで大丈夫です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3157044/6d3b8150-363a-476b-e070-d68ee56fe68e.png)

コントローラにアクションを記述していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3157044/d888a626-fc0e-3c14-e5a3-f79ea6f8a1a0.png)

createアクションでは@bookのidと現在ログインしているユーザーのidを使って新しくfavoritesを作成し、saveメソッドにより保存しています。
destroyアクションではcreateと同様にそれぞれのidでfavoritesを探し、destoroyメソッドで削除しています。

6.view
いよいよviewにいいねボタンを追加します。
本の詳細ページに38から50行目を追加してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3157044/33a9f9d9-9d49-029a-dd35-88be1251ac41.png)

ここでifの条件文に注目してください。faavorited_by?はコチラで新しく追加したメソッドであり、bookモデルに以下のように記述します。
もしこのメソッドが働いたとき、favorited_by?の後の()の中身をuserとして受け取り、そのuserのidでんおいいねが存在するかを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3157044/ce35c95d-8f04-430d-3a5d-ce24df2064ec.png)

これにより、いいねが既に存在するならdeleteのアクションが働き、まだ存在しないのならelseの後のcreateが働くような記述になっています。

これらの作業が完了したらサーバーを立ち上げて、正常に機能するか確認してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3157044/e24d4447-b078-3089-27e0-0cd4f7515610.png)


7.非同期通信化
ここからが本番です！今のままですといいねをするといちいちページがリロードされるため、使い勝手があまりよろしくありません。
そこで、いいね機能を非同期通信に対応させることで、いいねをしてもリロードを挟まないようにします。

まずはjQueryをインストールします。以下のコマンドでインストールを行ってください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3157044/4e99958c-43fe-a34f-34a6-35e620e6c54a.png)

config/webpack/environment.jsに3~11行目を追加してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3157044/a0bb42d1-4a09-f257-cdec-f71479f65827.png)

app/javascript/packs/application.jsを以下のように変更してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3157044/0487c880-8992-0fb4-f0b9-607542aef86a.png)

これによってjqueryを導入することができました。

次は、非同期通信により変化するいいねボタンを部分テンプレート化します。
app/views/books/show.html.erb
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3157044/a3ad3362-6bcd-11ce-eb6f-058d1f91c586.png)

app/views/favorites/_favorite.html.erb
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3157044/4b8e8f99-f5c9-c763-dd45-c1b97829590a.png)


テンプレートにはremote: trueを追加することを忘れないでください。これが非同期通信のトリガーになります。
これによりjsファイルを開くことができ、ページがリロードされることなく、情報が更新されます。

jsファイルはcreateとdestoroyでそれぞれviews/favoritesフォルダに作成して、それぞれに以下の記述を追加してください。

app/views/favorites/create.js.erb
$('#favorite_<%= @book.id %>').html("<%= j(render partial: 'favorites/favorite', locals: {book: @book}) %>");

app/views/favorites/destroy.js.erb
$('#favorite_<%= @book.id %>').html("<%= j(render partial: 'favorites/favorite', locals: {book: @book}) %>");

これにて非同期でいいね機能を追加することができました。


8.終わりに
非同期通信は少しわかりにくく、ネットで探してもrails5用のもので上手くいかないことがありました。今回はrails6用として
アウトプットする形で記事を投稿しました。
わかりにくい部分、間違えている部分などありましたらコメントいただけますと幸いです！