14
18

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 5 years have passed since last update.

Rails x Ajaxでスマートに「もっと見る機能」を実装する

Posted at

はじめに

  • 巷でよく見るAjaxでの「もっと見る」機能を一つのページ内で複数種類設置する依頼が来て、色々調べたので共有。
  • 完成形としてはこんな感じになります。(見やすさ的に1つずつ出すようにしていますが、適宜数は変えられます)

  • 予備知識として以下のものを頭に入れておく必要があります。
  1. Kaminariによるページネーション。
  2. RailsのAjax通信。(index.js.erbのこととか)
  3. BootStrap4(ビューの整形に使っているだけなので、詳しくなくていいけども)
  4. Slimテンプレート(3と同様)

環境

$ ruby -v
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux]

$ rails -v
Rails 5.2.1

準備

  • 以下のものを必要とします。
gem 'kaminari'
# seedを使うなら
gem 'seed-fu' 

実装

モデル

  • ここでは例としてDogCatを使いますが、存在としてあればいいので実装は割愛します。
  • seed-fuとかを使って、前もってページネーション用のインスタンスをDBに作っておきましょう。

コントローラー

  • まずはコントローラーから。今回のページをsample#indexアクションとします。
  • このアクションでは、**htmlフォーマット(通常)jsフォーマット(Ajax)**の二種類のリクエストを扱うことになります。
  • 通常アクセスの場合はguardreturn unless request.xhr?)で止まるので、インスタンス変数を受け取ってページをレンダーするだけです。
  • しかしAjax通信の場合はguardを通過して、params[:type]毎に、異なるJSファイルを実行します
  • JSファイルの中には、**「特定の一覧リストに新しい要素をAppendして、特定の「もっと見る」ボタンを更新する」**処理が入っているため、渡したパラメーターによって挙動を変えることができるのです。
class SampleController < ApplicationController
  def index
    @dogs = Dog.all.page(params[:page]).per(1)
    @cats = Cat.all.page(params[:page]).per(1)

    # これ以下はAjax通信の場合のみ通過
    return unless request.xhr?

    case params[:type]
    when 'dog', 'cat'
      render "sample/#{params[:type]}"
    end
  end
end

ビュー

  • ビューは今回の場合、全部で5つ用意します。
app/views/sample/
├── _cat.html.slim
├── _dog.html.slim
├── cat.js.erb
├── dog.js.erb
└── index.html.slim
  • 基本私はSlimを使っているのですが、JSファイルを書く際にはErbで書くことを強くお勧めします。(調べたらわかりますがとても描きにくい‥‥)
  • 余談ですが、Slim使ってても、拡張子にerbってつければ動いてくれるのでとても助かってます!

HTMLフォーマット側

/ index.html.slim
.container.my-5
  .row
    .col-md-6
      #dog-list
        = render partial: 'sample/dog', collection: @dogs
        = link_to_next_page @dogs, 'もっと見る', id: 'more-dog', class: 'btn btn-light w-100', params: { type: :dog }, remote: true
    .col-md-6
      #cat-list
        = render partial: 'sample/cat', collection: @cats
        = link_to_next_page @cats, 'もっと見る', id: 'more-cat', class: 'btn btn-light w-100', params: { type: :cat }, remote: true
/ _cat.html.slim, _dog.html.slim (cat -> dogに書き換えるだけ)
.border.mb-1
  p cat
  • パーシャルビューに関しては、存在が確認できればいいだけなので適当です。
  • ポイントは以下の通り。
    • それぞれのリストが入る大元のDivタグユニークなIDを付与。
    • link_to_next_pageメソッドにユニークIDtypeパラメーターを付与。

JSフォーマット側

/ cat.js.erb, dog.js.erb (cat -> dogに書き換えるだけ)
$('#more-cat').remove();
$('#cat-list').append("<%= j render partial: 'sample/cat', collection: @cats %>")
$('#cat-list').append("<%= j link_to_next_page(@cats, 'もっと見る', id: 'more-cat', class: 'btn btn-light w-100', params: { type: :cat }, remote: true) %>")
  • ご覧の通り、特定のリストに新しい要素を追加しているだけです。
  • Ajaxを呼ぶたびに「もっと見る」ボタンが更新され、もしこれ以上データがないようであれば自動でレンダーされなくなります神かよ

おわりに

  • こんな感じで想像以上にすっきりとAjaxでの「もっと見る」を実装することができるようになりました。
  • 今回は1ページに「もっと見る」が二つという特殊な場合を扱いましたが、別に一つでも全然動きます。
  • 皆様良いRailsライフをー👍
14
18
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
14
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?