25
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Rails】ページネーションをAjax対応にする

Last updated at Posted at 2020-10-20

#1.はじめに
 現在作成中のWebアプリケーション(育児サイトーSUKUSUKUー)のホーム画面のページネーションについて、別ページに移動する際、いちいちリロードされて、ページ上部に移動されるのがストレスに感じました。なのでページネーションをAjax対応にして、使いやすくしたいなと考えました。
ezgif-7-71eb2ec20490.gif

  この記事でわかること
    ・Ajax通信の基本的な仕組み
    ・代表的なJavaScriptライブラリ
    ・RailsにおけるAjax
    ・ページネーションをAjax対応にする

#2.そもそもAjaxとはなにか?
 Ajax(エイジャックス、アジャックス)とは、wikipediaによると、

ウェブブラウザ内で非同期通信を行いながらインターフェイスの構築を行うプログラミング手法である。
XMLHttpRequest(HTTP通信を行うためのJavaScript組み込みクラス)による非同期通信を利用し、通信結果に応じてダイナミックHTML (DHTML) で動的にページの一部を書き換えるというアプローチを取る。
AjaxはAsynchronous JavaScript + XML の略で、2005年2月18日に米国のインフォメーションアーキテクトであるJesse James Garrettにより名付けられた。

とのこと。もう少し詳しく説明していきます。

####非同期通信とは?

 同期通信あっての非同期通信なので、まずは同期通信について説明します。同期通信では下記の図のようにユーザーインターフェイス上でなんらかの操作し、そのリクエストをWebサーバーへ送ります。そして、Webサーバーはそのレスポンスを受取り、データベース等で処理を行い、その結果をHTML,CSS等のレスポンスでブラウザ側へ送信します。ブラウザはリロードされ、結果が表示されます。

名称未設定ファイル.png

 同期通信の地図アプリでは、現在表示している位置から、移動したり、拡大した場合、ブラウザはリロードされていました。

r20imasara03_01.gif

 非同期通信では、JavaScriptを使用しウェブブラウザ内で動的な処理が行なえます。下記の図のようにユーザーインターフェイス上で何らかの処理を行った際に、直接サーバーへ通信を行うのではなく、ブラウザ内のAjaxエンジンへJavaScriptの呼び出しを行います。AjaxエンジンはレスポンスとしてHTML,CSSをユーザーインターフェイスへ送り、DOMがブラウザへ表示されます。この時点ではブラウザとサーバー同じ状態ではないため、AjaxエンジンよりWebサーバーへ**XMLHTTPリクエスト(XHR)**を送ります。リクエストを受け取った結果をサーバー側はXML、JSONとしてレスポンスします。

非同期通信.png

 非同期通信の地図アプリでは、現在表示している位置から、移動したり、拡大した場合、ブラウザ側でリロードされずに動的な処理ができます。

ezgif-4-050dab99fd38.gif

つまり、

同期通信:サーバーの通信を待ってからブラウザがリロードされ動的な処理ができる。

非同期通信:サーバーの通信を待たずに、動的な処理ができる。その際ブラウザはリロードされない。

ということです。

####XMLとは?
 Extensible Markup Languageの略。マークアップ言語の一つ。HTMLはWebページを表示するための言語に対して、データを交換するためや設定ファイルを書くときに使用する言語です。タグなどを自由に編集できるため、「拡張可能なマークアップ言語」とよばれます。

<?xml version="1.0" encoding="UTF-8" ?>
<食料品>
  <食料>
    <名前>リンゴ</名前>
    <色></色>
  </食料>
</食料品>

このようにタグは日本語でも記述可能です。

####JSONとは?
 JavaScript Object Notationの略。 XMLと同様の共通データ定義言語です。人間にとって読み書きが容易で、マシンにとっても簡単にパースや生成を行なえる形式です。

参考にしました→JSONの紹介

####DOMとは?
 Document Object Modelの略。HTMLやXML文書のためのプログラミングインターフェイスです。DOMはHTMLやXMLをツリー構造として展開します。AjaxではDOMを使用してユーザーインターフェイスの一部分だけ書き換えます。

参考にしました→DOMの紹介

#3.Ajaxを使用するメリット、デメリット
####メリット
 ・サーバーからのレスポンスを待たずに、高速に動的な処理ができる。

 ・受信するデータ量が減らせる。

 ・サーバーに負担がかからない。

####デメリット
 ・開発の際、ブラウザがリロードされないため、エラーメッセージが画面に表示されない。エラーがどこに出てるか分かりづらい。

 ・クロスブラウザ対策[^1]が必要

 ・バリデーションをJS,サーバーサイド両方で記載しないといけない。

主に、メリットはユーザー側にあり、デメリットは開発側にありそうですね。

#4.JavaScriptのフレームワーク
 Ajaxを使用するためにはJavaScriptを学ぶ必要があります。JavaScriptを書きやすくするフレームワークがいくつかありますので、ここでは代表的なものを紹介します。

####jQuery
 Ajax処理を簡単にするために最もよく利用されてきたフレームワーク。
 文法も簡単でシンプルなので覚えやすい。ブラウザの種類に依存せず、アニメーションから効果、非同期通信に関わる部分まで幅広く対応することができます。

####Angular
 Googleと個人や企業のコミュニティによって開発されているフレームワーク。主に大規模なアプリケーションに向いている。
 独自の概念や機能が多く有るので、学習コストは高め。

####React
 Facebookとコミュニティによって開発されているフレームワーク。
 UI部分のみのライブラリなので、他のフレームワークと併用してしようする。
 その代わり動作は早い。

####Vue.js
 シンプル・軽量・高速。強力なコンポーネント機能により、データや処理を分けることができ、サーバーとの通信も高速で行うことができる。

#5.RailsにおけるAjax
 Railsでは、JavaScriptをDOMに追加する際の手法を**「UJS: Unobtrusive(控えめな)JavaScript」**と呼んでるそうです。
 これはHTML上にJavaScriptを混入させると、DRY[^2]の原則に反することが多くなる上に、煩雑になり保守がしづらくなります。そのためJavaScriptを正しく分離し表に出さない手法をRailsではとっています。Railsでは、こうした「最小化」と「連結」によって、あらゆるJavaScriptを実行できます。
 実際にリンクにJavaScriptを組み込むには、ビュー上で下記のようにremoteオプションをオンにします。

<%= link_to "記事", @article, remote: true %>

これでJavaScriptを組み込む事ができます。
 
参考→Rails で JavaScript を使用する

#6.ページネーションをAjax対応にする

####環境

  • MacBook Catalina ver.10.15.7

  • Rails 6.0.3

  • ruby 2.7.1

  • gem "kaminari"

  • jQuery

今回は学習コストを考慮しフレームワークはjQueryを使用することとしました。

####RailsにjQueryを入れる
 まず、WebpackとYarnこの両方にjQueryを追加する必要があります。

ターミナル
$ yarn add jquery
config/webpack/environment.js
const { environment } = require('@rails/webpacker')

const webpack = require('webpack')
environment.plugins.prepend('Provide',
  new webpack.ProvidePlugin({
    $: 'jquery/src/jquery',
    jQuery: 'jquery/src/jquery'
  })
)

module.exports = environment

application.jsファイルでjQueryをrequireします。

app/javascript/packs/application.js
require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")
require("jquery")

これで、RailsでjQueryを使用できます。

####ビュー(HTML)

 最初にビューをAjax対応できるようにします。

app/views/static_pages/home.html.erb
ー ページネーション部分だけ記載 ー
  .
  .
<div class="question-index">
  <%= paginate @questions, remote: true %>
    <%= render partial: 'questions/question', collection: @questions %>
  <%= paginate @questions, remote: true %>
</div>
  .
  .

pagenateremote: trueを記載します。
このhome.html.erbで生成されるページネーションのHTMLが下記です。

HTML
<ul class="pagination">
  <li class='active'>
    <a data-remote="true">1</a>
  </li>
  <li>
    <a rel="next" data-remote="true" href="/?page=2">2</a>
  </li>
  <li>
    <a rel="next" data-remote="true" href="/?page=2">&rsaquo;</a>
  </li>
  <li>
    <a data-remote="true" href="/?page=2">最後 &raquo;</a>
  </li>
</ul>
```

すべてのページネーションのリンクに``data-remote="true"``が付きました。
この事により、JavaScriptによるフォーム操作を許可することをRailsに知らせることができます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687088/0cb6e3b0-2b9f-c5cc-3fd1-ef28f16e879d.png" width="30%">
↑生成されたページネーション。

####コントローラー

次にコントローラーでAjaxリクエストに応答できるようにします。

```ruby:app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController

  def home
    @questions = Question.page(params[:page]).per(10).all
    respond_to do |format|
      format.html
      format.js
    end
  end

end
```

``respond_to``メソッドはブロック内のコードの内いずれか一つがが実行されます
普段はレスポンスとして``format.html``が呼び出されますが今回ページネーションのリンクは``data-remote="true"``として``remote``オプションがオンになっているため、``format.js``がよびだされます

####ビューHTML
最後にjQueryを使用してAjax対応させます
その前にjQueryで呼び出しできるようhome.html.erbに記載されているコードをパーシャルに移します

```HTML:app/views/static_pages/home.html.erb見直し
<div id="home_pagenate">
  <%= render partial: 'index_page' %>
</div>
```

元あったhome.html.erbのコードをパーシャルへ貼り付けます。

```HTML:app/views/static_pages/_index_page.html.erb
ー ページネーション部分だけ記載 ー
  .
  .
<div class="question-index">
  <%= paginate @questions, remote: true %>
    <%= render partial: 'questions/question', collection: @questions %>
  <%= paginate @questions, remote: true %>
</div>
  .
  .
```

JSファイルを作成し、jQueryのコードを記載します。

```javascript:home.js.erb
 $('#home_pagenate').html("<%= escape_javascript(render 'index_page') %>");
```
これで、``data-remote="true"``の記載があるページネーションが実行された際に、コントローラーでJSファイルが呼び出され、JSファイルで元あったページがレンダリングされます。これでAjax対応は完成です。

####完成形

![ezgif-6-bfbd4116adbc.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687088/7e84ee1e-7dfc-e6bf-3665-e6a201675750.gif)

もっと簡単なやり方がありそうですが、とりあえずうまく動きました!!

#7.まとめ
 Rubyの勉強はそこそこやってましたが、JavaScriptはよく知らなかったのでまとめました。そこそこ学習コストは高い上に、初学者にとって保守が難しそうなので、必要な部分を見極めたいです。

[^1]: すべてのブラウザで動作する保証。
[^2]: Don't Repeat Yourself「繰り返しを避けること」
25
17
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
25
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?