LoginSignup
2
2

More than 1 year has passed since last update.

お気に入り機能の実装

Last updated at Posted at 2021-05-14

目次

1.はじめに
2.いいねボタンの導入
3.同期通信で実装する
4.非同期通信で実装する
5.おわりに

1. はじめに

今回は同期通信で実装した後、それをもとに非同期通信に切り替えていきます。まずは必要なものを導入しましょう。

2. いいねボタンの導入

font-awesome-railsを導入しましょう。もし文字をクリックしてお気に入り機能を実装する場合であれば3.同期通信で実装するから実装していただいて問題ないです。以下のようにアイコンをクリックしてお気に入りをつけたり外したりしたい場合はこちらを参考にしてください。
52a7c16510cbb3fd2f8095bae614ab1e.gif

1. GEMの導入

gemfile
gem 'font-awesome-rails'

*導入したら必ずbundle installしてください。

2. CSSファイルに記述を追加する

app/assets/stylesheets/application.css
*= require font-awesome

これで使う準備はOKです。

3. 使用したいビューファイルに記述を追加する

ビューファイル
<i class="fa fa-アイコン名" aria-hidden="true"></i>

どんなアイコンを使用するかはご自由に!!
ここをクリック!から探してね!!

3. 同期通信で実装する

アプリケーション作成、ユーザー登録、投稿機能ができている体で進みます。そこまでは自力で実装してください。

1. お気に入り機能に必要なものを揃える

まずは必要なもの...そうですコントローラーとモデルですね!
どんな名前でもいいので作成してください。今回この記事ではlikeという名前で実装してます。

2. ルーティングの設定

今回は投稿機能に関連する機能のため、ネスト構造で設定します。今回はお気に入りをつけて外すだけなのでcreatedestroyのみ記述してます。

routes.rb
 Rails.application.routes.draw do
  #(省略)
  resources :posts do
    resources :likes, only: [:create, :destroy]
  end
 end

3. モデルの設定

まず、マイグレーションファイルにはuser_idpost_idが保存できるように設定してマイグレートしておいてください。
今回1人のユーザーはお気に入りを何回もすることができます。また、投稿された物に対してもたくさんお気に入りすることができます。
そのため以下のようにアソシエーションを設定します。

app/models/like.rb
class Like < ApplicationRecord
  belongs_to :user
  belongs_to :post

end
app/models/user.rb
#以下を追加する
has_many :likes
app/models/post.rb
#以下を追加する
has_many :likes

4. コントローラーの設定

まずはお気に入りを登録するcreateアクションの設定です。
今回は投稿したpostに対して行いたいためまずはどのpostなのかを取得する必要があります。その後、そのpostに対してお気に入りを新しく作り、保存ができたらトップページに戻るように設定します。

お気に入りの削除は今の考え方で、保存ではなく削除したら...の場合で記述しましょう。
以下のようになります。

likes_controller.rb
class LikesController < ApplicationController
 before_action :set_post
  def create
    @like = Like.new(user_id: current_user.id, post_id: params[:post_id])
    @like.save
    redirect_to root_path
  end

  def destroy
    @like = current_user.likes.find_by(post_id: @post.id)
    @like.destroy
    redirect_to root_path
  end

private

  def set_post
    @post = Post.find(params[:post_id])
  end
end

5. ビューファイルの設定

お気に入り機能だけを別に切り出したいので今回私は部分テンプレートに記述しました。そのため、元々の記述の部分は以下のようになります。

views/posts/index.html.erb
#(省略)
<div class="likes_heart" id="post_<%= post.id %>">
   <%= render "likes/like", post: post %> 
</div>

部分テンプレートでは、以下の条件をつけました。
・ログインしていないとお気に入りできない
・1投稿に対して1回しかお気に入りができない(既にお気に入りに登録していたら削除するボタンになる)

likes/_like.html.erb
<% if user_signed_in? %>
  <% if post.liked_by?(current_user) %>
    <%=link_to post_like_path(post_id: post.id, id: post.id), method: :delete do%>
      <i class="fa fa-heart" aria-hidden="true" id="heart"></i>
      <%= post.likes.count %>
    <% end %>
  <% else %>
    <%=link_to post_likes_path(post), method: :post do%>
      <i class="fa fa-heart" aria-hidden="true" id="heart"></i>
      <%= post.likes.count %>
    <% end %>
  <% end%>
<% end %>

また、今回liked_byというメソッドを使用します。whereメソッドを使用し、likesテーブルに「user_id」が存在しているかどうか検索をかけています。(存在すれば削除、存在しなければお気に入り追加、と振り分ける)

app/models/post.rb
#省略
def liked_by?(user)
    likes.where(user_id: user.id).exists?
end

同期通信はこれで終わり!!!実際に動かしてみてください!!

4. 非同期通信で実装する

ここが本当に難しい...と感じました!もう少し!頑張りましょう!!

1. コントローラーの修正

非同期通信に変更するのでトップページに遷移させる記述を削除しましょう。
以下のようになります。

likes_controller.rb
class LikesController < ApplicationController
  before_action :set_post

  def create
    @like = Like.new(user_id: current_user.id, post_id: params[:post_id])
    @like.save
  end

  def destroy
    @like = current_user.likes.find_by(post_id: @post.id)
    @like.destroy
  end

  private

  def set_post
    @post = Post.find(params[:post_id])
  end

end

2. ビューファイルの設定

「remote: true」を付与します。付与することで、パラメーターがHTML形式ではなくJS形式で送られるようになります。
今回の場合は「remote: true」をlink_toメソッドに付与することで、likes_controller.rbのcreateアクション後は、views/likes/create.js.erbが呼び出されるようになります。

views/likes/_like.html.erb
<% if user_signed_in? %>
  <% if post.liked_by?(current_user) %>
    <%=link_to post_like_path(post_id: post.id, id: post.id), method: :delete,remote: true do%>
      <i class="fa fa-heart" aria-hidden="true"></i>
      <%= post.likes.count %>
    <% end %>
  <% else %>
    <%#link_to post_likes_path(post), method: :post do%>
    <%= link_to post_likes_path(post), method: :post, remote: true do%>
      <i class="fa fa-heart" aria-hidden="true"></i>
      <%= post.likes.count %>
    <% end %>
  <% end%>
<% end %>

3. js.erbファイルの作成

今回は2つ用意しましょう。
記述は以下です。

views/likes/create.js.erb
document.getElementById('post_<%= @post.id %>').innerHTML = '<%= j(render 'like' ,post: @post) %>'
views/likes/destroy.js.erb
document.getElementById('post_<%= @post.id %>').innerHTML = '<%= j(render 'like' ,post: @post) %>'

詳しくみていきましょう。
まずはこちらです。

document.getElementById('post_<%= @post.id %>')

書き換えたいビューのIDを取得しています。
IDに関しては、3.同期通信で実装する5.ビューファイルの設定で設定してますので確認してください。

'<%= j(render 'like' ,post: @post) %>'

部分テンプレートの内容に置き換えることを表してます。
今回使用した部分テンプレートは_like.html.erbなのでこのような書き方です。部分テンプレートに保存/削除した内容を渡さないといけないので、部分テンプレート内で使用している変数post: @postを記述してます。

5. おわりに

普通にJSファイルを作成して行うやり方もあると思います。皆さんがしっくりくるやり方で実装してみてください!!

2
2
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
2
2