はじめに
- 巷でよく見るAjaxでの「もっと見る」機能を一つのページ内で複数種類設置する依頼が来て、色々調べたので共有。
- 完成形としてはこんな感じになります。(見やすさ的に1つずつ出すようにしていますが、適宜数は変えられます)
- 予備知識として以下のものを頭に入れておく必要があります。
- Kaminariによるページネーション。
- RailsのAjax通信。(
index.js.erb
のこととか) - BootStrap4(ビューの整形に使っているだけなので、詳しくなくていいけども)
- 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'
実装
モデル
- ここでは例として
Dog
とCat
を使いますが、存在としてあればいいので実装は割愛します。 -
seed-fu
とかを使って、前もってページネーション用のインスタンスをDBに作っておきましょう。
コントローラー
- まずはコントローラーから。今回のページを
sample#index
アクションとします。 - このアクションでは、**htmlフォーマット(通常)とjsフォーマット(Ajax)**の二種類のリクエストを扱うことになります。
- 通常アクセスの場合は
guard
(return 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
メソッドにユニークID
とtypeパラメーター
を付与。
- それぞれのリストが入る
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ライフをー👍