現在RubyとJavaScriptを用いて記事投稿サイトを作成しています。
今回は非同期通信のお気に入り登録を実装します。
お気に入り記事一覧ページの実装までを書いていきたいと思います。
■仕様等
・お気に入りアイコンをクリックで登録/解除
・jQueryを使用しない
###■お気に入り機能
####①Userモデルにお気に入り操作に関するメソッドを記述
bookmarkモデル、コントローラーを作成した後、
お気に入り操作に関するメソッドをuserモデルに追記していきます。
※bookmarksテーブルのカラムはuser_idとarticle_idです。
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に存在するかを判定します。
####②ルーティングの設定
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を指定します。
####③コントローラーの設定
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モデルで設定した各メソッドの引数に、対象の記事情報を渡しています。
####④ビューの記述
<% @articles.each do |article| %>
<div class="article-content" id="article_<%= article.id %>">
<%= render 'shared/articles', article: article %>
</div>
<% end %>
<% if user_signed_in? %>
<% if current_user.bookmark?(article) %>
<%= render 'bookmarks/unbookmark', article: article %>
<% else %>
<%= render 'bookmarks/bookmark', article: article %>
<% end %>
<% end %>
###■非同期処理の設定
<%= link_to bookmarks_path(article_id: article.id), class: "bookmark", id: "js-bookmark-button-for-article-#{article.id}", method: :post, remote: true do %>
<% end %>
<%= 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
に遷移します。
document.getElementById('article_<%= @article.id %>').innerHTML = '<%= escape_javascript( render 'shared/articles', article: @article ) %>'
document.getElementById('article_<%= @article.id %>').innerHTML = '<%= escape_javascript( render 'shared/articles', article: @article ) %>'
対象の記事を取得して、index.htmlにもあるrenderの部分を挿入しています。
escape_javascript
は改行のエスケープ処理を行います。
以上でお気に入り登録を実装することができました。
###■お気に入り一覧表示ページの実装
####①ルーティングの設定
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
を記述します。
####②コントローラーの設定
def bookmarks
@bookmarks_articles =
current_user.bookmarks_articles.includes(:user).order('created_at DESC')
end
current_user.bookmarks_articles
現在のユーザーの全てのお気に入り記事を取得しています。(冒頭のUserモデルにて設定)
####③ビューを記述
<% @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