ransackという便利な検索用のgemがありますよね
参考:Ransackのススメ
複雑な条件の検索をわざわざ自分で書かなくても簡単に実装できます.
ハッピーですね
これをajaxを使ってページ遷移せずに検索結果を反映させることができれば
もっとハッピーですね
ストレスのない検索に加えて、裏側で処理することでransackあるあるの汚いパラメータを見なくて済むこともメリットの1つだと思います!
今回はサンプルアプリケーションを作ってみます。
環境
- Rails 5.0.4
- ruby 2.3.3
サンプルアプリケーション作成
rails new
$ rails new ajax-ransack
$ cd ajax-ransack
Gemfile編集
Gemfileに以下を追記する
gem 'ransack' # 言うまでもなくransack
gem 'haml-rails'# htmlを楽に書くために使います。
gem 'faker' # ダミーデータ作成に使います。
$ bundle
UserのModelなど作成
$ rails g scaffold User name:string email:string description:text age:integer sex:string
$ rails db:migrate
適当にname,email,description,age
などのカラムを持ったユーザーを作成します。
ダミーデータ作成
検索してなんぼですので、ダミーデータを作成します。
参考:fakerとforgeryを使ってダミーデータを生成する
100.times do
User.create(name:Faker::Name.name,email: Faker::Internet.email,description:Faker::Job.title,age:Faker::Number.between(1,100),sex:Faker::Demographic.sex)
end
$ rails db:seed
これでそれらしきデータは入りました
Controller
...
def index
@q=User.search(params[:q])
@users=@q.result
# ajaxで送られた場合にはjsonを変えす
unless params[:q].blank?
render json: @users.select("id").map { |e| e.id }.to_json
end
end
...
View
%h1 Listing users
=search_form_for @q,remote: true,:id=>"user_form" do |f|
名前
=f.text_field :name_cont
男性
=f.radio_button :sex_in_any,"Male"
女性
=f.radio_button :sex_in_any,"Female"
email
=f.text_field :email_cont
○歳以上
=f.number_field :age_gt
=f.submit
:coffee
$ ->
-# テキストフィールの変更を察知してsubmit
$("#user_form").keyup ->
$("#user_form").find("input[type='submit']").click()
-# フォームのinputタグの変更をsubmit
$("#user_form").change ->
$("#user_form").find("input[type='submit']").click()
-# ajaxの結果を受け取って実行する
$('#user_form').on 'ajax:success', (event, results) ->
$select=$("#user_check")
$trs=$select.find("tr")
$trs.each ->
# idを読み取りInt型に変換する
value=parseInt($(this).find("td").first().text())
-# idが結果に含まれていたら表示する
if value in results
$(this).show()
else
$(this).hide()
%table
%thead
%tr
%th id
%th Name
%th Email
%th Description
%th Age
%th sex
%th
%th
%th
%tbody#user_check
- @users.each do |user|
%tr
%td= user.id
%td= user.name
%td= user.email
%td= user.description
%td= user.age
%td= user.sex
%td= link_to 'Show', user
%td= link_to 'Edit', edit_user_path(user)
%td= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' }
解説
そもそもsubmitボタンを押す前に勝手に検索結果を反映させる方がかっこいいと思ったのでそうしてます。
keyupでテキストフィールドの変更を取得
$("#user_form").keyup ->
$("#user_form").find("input[type='submit']").click()
changeでラジオボタンの変更を取得
$("#user_form").change ->
$("#user_form").find("input[type='submit']").click()
ラジオボタン以外にも全てのinput要素に対して反応します。
テキストフィールドの場合、フォーカスが外れないと反応しないためリアルタイム性を追究するのであれば、keyupを利用することになります。
ajaxの結果を受け取る
$('#user_form').on 'ajax:success', (event, results) ->
こんな感じでajaxの結果を受け取ります。今回はresultsの中にidの配列が入っています。
そんでもってidが含まれていたらshow()
なければ、hide()
という感じでやっています!
今回の実装は絞込に重きを置いてるため、idだけのやり取りとなっており、要素自体はページを最初に開いたときのを利用しています。
必要なデータだけを取りだす場合は、show(),hide()ではなく、一回全部中身を消した後に、appendとかしていく感じになるかなと。
サンプルのリンク
ご指摘、真摯に受け止めますのでぜひぜひよろしくお願いします〜!