1
1

More than 3 years have passed since last update.

お気に入り登録を実装(非同期通信)

Last updated at Posted at 2021-06-02

現在RubyとJavaScriptを用いて記事投稿サイトを作成しています。
今回は非同期通信のお気に入り登録を実装します。
お気に入り記事一覧ページの実装までを書いていきたいと思います。

■仕様等
・お気に入りアイコンをクリックで登録/解除
・jQueryを使用しない

■完成後の動作

Image from Gyazo

■お気に入り機能

①Userモデルにお気に入り操作に関するメソッドを記述

bookmarkモデル、コントローラーを作成した後、
お気に入り操作に関するメソッドをuserモデルに追記していきます。
※bookmarksテーブルのカラムはuser_idとarticle_idです。

user.rb
         has_many :bookmarks_articles, through: :bookmarks, source: :article
         def bookmark(article)
           bookmarks_articles << article
         end

         def unbookmark(article)
           bookmarks_articles.delete(article)
         end

         def bookmark?(article)
           bookmarks_articles.include?(article)
         end

1行目
has_many :bookmarks_articles, through: :bookmarks, source: :article
ユーザーがお気に入り登録した記事を全て取得します。
2行目〜4行目
bookmark(article)
引数に渡された記事情報を1行目のbookmarks_articlesに追加します。
6行目〜8行目
unbookmark(article)
引数に渡された記事情報を1行目のbookmarks_articlesから削除します。
10行目〜12行目
bookmark?(article)
引数に渡された記事情報が1行目のbookmarks_articlesに存在するかを判定します。

②ルーティングの設定

routes.rb
Rails.application.routes.draw do
  devise_for :users
  root to: "articles#index"
  resources :bookmarks, only: [:create, :destroy]
end

3行目
resources :bookmarks, only: [:create, :destroy]
お気に入りの登録と解除を実装するので、createとdestroyを指定します。

③コントローラーの設定

bookmarks_controller.rb
class BookmarksController < ApplicationController
  def create
    @article = Article.find(params[:article_id])
    current_user.bookmark(@article)
  end

  def destroy
    @article = current_user.bookmarks.find_by(id: params[:id]).article
    current_user.unbookmark(@article)
  end
end

4行目/9行目
current_user.bookmark(@article)
current_user.unbookmark(@article)
userモデルで設定した各メソッドの引数に、対象の記事情報を渡しています。

④ビューの記述

index.html
    <% @articles.each do |article| %>
      <div class="article-content" id="article_<%= article.id %>">
        <%= render 'shared/articles', article: article %>
      </div>
    <% end %>
_articles.html
<% if user_signed_in? %>
  <% if current_user.bookmark?(article) %>
    <%= render 'bookmarks/unbookmark', article: article %>
  <% else %>
    <%= render 'bookmarks/bookmark', article: article %>
  <% end %>
<% end %>

■非同期処理の設定

_bookmark.html
<%= link_to bookmarks_path(article_id: article.id), class: "bookmark", id: "js-bookmark-button-for-article-#{article.id}", method: :post, remote: true do %>
<% end %> 
_unbookmark.html
<%= link_to bookmark_path(current_user.bookmarks.find_by(article_id: article.id)), class: "bookmark", id: "js-bookmark-button-for-article-#{article.id}", method: :delete, remote: true do %>
<% end %> 

各1行目
<%= link_to bookmarks_path(article_id: article.id), class: "bookmark", id: "js-bookmark-button-for-article-#{article.id}", method: :post, remote: true do %>
<%= link_to bookmark_path(current_user.bookmarks.find_by(article_id: article.id)), class: "bookmark", id: "js-bookmark-button-for-article-#{article.id}", method: :delete, remote: true do %>
各末尾のオプションに注目してください。
remote:trueを設定することでJavaScript形式のリクエストが送信されます。
送信後、コントローラーのcreate/destroyアクションが実行されると、
create.js.erb/destroy.js.erbに遷移します。

create.js.erb
document.getElementById('article_<%= @article.id %>').innerHTML = '<%= escape_javascript( render 'shared/articles', article: @article ) %>'
destroy.js.erb
document.getElementById('article_<%= @article.id %>').innerHTML = '<%= escape_javascript( render 'shared/articles', article: @article ) %>'

対象の記事を取得して、index.htmlにもあるrenderの部分を挿入しています。
escape_javascriptは改行のエスケープ処理を行います。

以上でお気に入り登録を実装することができました。

■お気に入り一覧表示ページの実装

Image from Gyazo

①ルーティングの設定

routes.rb
Rails.application.routes.draw do
  devise_for :users
  root to: "articles#index"
  resources :articles do
    collection do
      get :bookmarks
    end
  end
  resources :bookmarks, only: [:create, :destroy]
end

4行目〜8行目
:articlesにネストする形でcollection do :bookmarks endを記述します。

②コントローラーの設定

articles_controller.rb
  def bookmarks
    @bookmarks_articles =
    current_user.bookmarks_articles.includes(:user).order('created_at DESC')
  end

current_user.bookmarks_articles
現在のユーザーの全てのお気に入り記事を取得しています。(冒頭のUserモデルにて設定)

③ビューを記述

bookmark.html.erb
    <% @bookmarks_articles.each do |article| %>
      <div class="article-content" id="article_<%= article.id %>">
        <%= render 'shared/articles', article: article %>
      </div>
    <% end %>

インスタンス変数を受け取って一覧を表示しています。

以上でお気に入り記事一覧表示ページの完成です。

参考記事

https://miiina01220.hatenablog.com/entry/2020/11/20/172739
https://techtechmedia.com/favorite-function-rails/
https://qiita.com/naberina/items/c6b5c8d7756cb882fb20

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