【Rails×Ajax】いいね機能ハンズオン


Ajaxで「いいね機能」を実装するハンズオン

1年以上内容を更新しておりませんので、最新の実装ではありません。ご了承ください。

はじめまして

こんにちは。
普段は餃子のことを考えながら DMM WEBCAMPの裏で 開発をしています。

DMM WEBCAMPはプログラミングスクールを運営しているのですが、よく生徒さんから
「Ajaxを取り入れたアプリケーションを作成したい」
「Ajaxが結局よくわからない」
「難しそう」
との声を頂くことが多く、折角なのでRailsのAjax処理の全体を見通しよく、そしてサクッと実装できるような記事を書き綴ってみました。ハンズオンになっているので、是非少しでも興味のある方は一緒にコーディングしながらAjaxの流れを掴んでいきましょう!

そもそもAjaxって...?

Ajax(エージャックス/エイジャックス)とは
「Asynchronous JavaScript + XML」の略です。
ちょっとさっぱりわからないですよね。
こちらのリンク先に丁寧な解説があるので読んでみてください。
初心者目線でAjaxの説明

Ajaxは部分的にデータを更新したり、画面の切り替えを行っています。
ちなみに、普段の生活の中でこんな場面よくありませんか。

最近のアプリケーションではAjaxの処理が多くの場面で取り入れられています。
TwitterやFacebook,QiitaのいいねもAjaxで処理されていますね。

では実際にRailsでは「いいね」を押した後(オレンジ色の矢印の部分)に、Rails側でどのような処理がされているのかイメージしながらコーディングしていきましょう。

RailsでAjax処理のいいね機能を実装しよう

  1. 実装の全体像を確認しよう
  2. 「いいね」機能のついたアプリケーションを準備
  3. 「いいね」をクリックした時に、Ajaxの処理をさせよう
  4. 部分テンプレートを作成しよう
  5. 部分的に更新させよう

1. 実装の全体像を確認しよう

まず先に実装の全体像を掴んでおきましょう。
先程の画像にあるオレンジ色の矢印は、このような処理をしています。

なんとなくイメージだけ掴んでおいてください。
難しくないので、要所要所追って進めていきましょう。

2. 「いいね」機能のついたアプリケーションを準備

まずは準備段階として、

  • ユーザー(User)
  • 投稿(Blog)
  • いいね(Like)

を実装した想定で進めます。

もし「いいね機能」「アソシエーション」が不安な方は、是非この記事を読んでみてください。丁寧すぎるくらい丁寧です。
【初心者向け】丁寧すぎるRails『アソシエーション』チュートリアル【幾ら何でも】【完璧にわかる】🎸

また簡素な「いいね機能」のついたアプリケーションをgithubに置いておくので、Ajaxを試してみたい方はご自由にご利用ください。
github:ajax_like_app

「いいね」機能が実装されているアプリケーションが作成できました。

ちなみに現在の「いいね」機能はAjaxではないので、「いいね」をクリックする度に
コントローラでリダイレクトされてページが更新されます。

左上のロードアイコンが更新されているように、ページが更新されています。

ここから、Ajax(非同期)で「いいね」を実装していきましょう。
たったの3ステップで実装できます。

3. 「いいね」をクリックした時に、Ajaxの処理をさせよう

それがめちゃめちゃ簡単です。
いいねを送信しているリンクにremote: true を追加しましょう。
こうすることで、「いいね」をクリックするとjs形式のリクエストを送信することができます。

index.html.erb
<% if blog.liked_by?(current_user) %>
     <p><span>お気に入り解除: </span><%=link_to blog.likes.count, blog_likes_path(blog.id), method: :delete, remote: true %></p>
<% else %>
     <p><span>お気に入り登録: </span><%=link_to blog.likes.count, blog_likes_path(blog.id), method: :post, remote: true %></p>
<% end %>

ページが更新される「いいね」の処理は、以下の画像のように
LikesControllerにHTMLリクエストが送信され、データベースにデータを保存・削除し、画面にリダイレクトする処理が行われています。

リンクにremote: true を指定すると
LikesControllerにjavascriptのリクエストが送信されます。
このままでは、まだ機能は完成していませんが、JSのリクエストを簡単に送ることが確認できました。

4. 部分テンプレートを作成しよう

図にすると次は②、③を行うのですが、すでにコントローラでLike.saveの処理をしているので、他に何か手を加える必要はありません。

そのため、④更新したい部分のビューを作成しましょう。

views/likes/_like.html.erb 部分テンプレートを作成します。
具体的には、部分的に更新したい「いいね」の箱を用意して、
「いいね」しているか、していないかという状態で表示を切り替えます。

このようなイメージです。

まずは更新するボックスを作成しましょう。
中身のrenderで「いいね」を切り替える処理を記述します。

views/blogs/index.html.erb
<div class="main_contents">
    <% @blogs.each do |blog| %>
        <div class="blog_contents">
          <h2><%= link_to blog.title, blog_path(blog.id) %></h2>
          <%= blog.body %>

         <!-- ↓追加(部分的に更新したい場所)↓ -->
          <div id="likes_buttons_<%= blog.id %>">
             <%= render partial: 'likes/like', locals: { blog: blog} %>
          </div>
         <!-- ↑ここまで↑ -->
        </div>
  <% end %>
</div>

index.html.erbで呼び出されるrenderの中身をみていきましょう。
ログイン中のユーザーがいいねしているかしていないかを判断して表示を切り替えています。

views/likes/_like.html.erb
<% if user_signed_in? %>
    <% if blog.liked_by?(current_user) %>
        <p><span>お気に入り解除: </span><%=link_to blog.likes.count, blog_likes_path(blog.id), method: :delete, remote: true %></p>
    <% else %>
        <p><span>お気に入り登録: </span><%=link_to blog.likes.count, blog_likes_path(blog.id), method: :post, remote: true %></p>
    <% end %>
<% else %>
    <p><span>お気に入り数: </span><%= blog.likes.count %></p>
<% end %>

remote: true で送信された値を
LikesControllerで受け取り、「いいね」を登録、または取り消します。
createアクションやdestroyアクションではビューを作成していないので、普通はリダイレクト処理でページに遷移させますが、
remote: trueでjavascript形式のリクエストを送信しているため、create.js.erb/destroy.js.erbファイルを作成し、部分的な更新をします。

views/likes/create.js.erb
// #likes_buttons_<%= @blog.id %>この部分のHTMLだけ、renderで部分的に更新するという処理です
$('#likes_buttons_<%= @blog.id %>').html("<%= j(render partial: 'likes/like', locals: {blog: @blog}) %>");
views/likes/destroy.js.erb
$('#likes_buttons_<%= @blog.id %>').html("<%= j(render partial: 'likes/like', locals: {blog: @blog}) %>");

5. 部分的に更新させよう

すでに90%完成しているのですが、まだLikeControllerでリダイレクト処理が残ってしまっているので、
削除しましょう。

LikesController
class LikesController < ApplicationController

  def create
    @blog = Blog.find(params[:blog_id])
    like = current_user.likes.build(blog_id: params[:blog_id])
    like.save
    redirect_to blogs_path #←この行を削除
  end

  def destroy
    @blog = Blog.find(params[:blog_id])
    like = Like.find_by(blog_id: params[:blog_id], user_id: current_user.id)
    like.destroy
    redirect_to blogs_path #←この行を削除
  end
end

大事なポイント

railsでjQueryを読み込めるようにgemをインストールしましょう。
これをインストールしないと、ページを更新しないといけなない仕様になってしまいます。

Gemfile
gem 'jquery-rails'

gemを追加したのでgemを読み込みましょう。

ターミナル・コマンドプロンプト
bundle install

また、application.jsにもjqueryをrequireします。

application.js
//
//= require jquery ←追加
//= require rails-ujs

サーバーを立ち上げて、実装できているか確認してみてください。
このようにページの更新なしで、「いいね」機能が実装できました。

最後に

RailsのAjaxは意外と簡単です。そんな気がしてきませんか。

3つのポイント
1. jsのリクエストを送信する(remote: true)
2. 部分テンプレートを作成する
3. リロードしない処理を設定(コントローラのredirect削除・jqueryインストール)

この記事を通してRailsのAjax処理の流れが簡単にイメージできるようになれば嬉しいです。
Ajaxを使えば「投稿」「表示」「更新」「削除」などのCRUDの処理を、リロードせずに実装することができます。是非興味のある方は挑戦してみてください。実装お疲れ様でした。

また、この記事に対して間違えている部分や
オススメの餃子屋さんがあれば、コメントして頂けると助かります。