LoginSignup
29
30

More than 5 years have passed since last update.

Ransackの検索結果をajaxで動的に反映させる方法

Last updated at Posted at 2017-06-23

ransackという便利な検索用のgemがありますよね

参考:Ransackのススメ

複雑な条件の検索をわざわざ自分で書かなくても簡単に実装できます.

ハッピーですね:blush:

これをajaxを使ってページ遷移せずに検索結果を反映させることができれば

もっとハッピーですね:blush::blush:

qiita.gif

ストレスのない検索に加えて、裏側で処理することでransackあるあるの汚いパラメータを見なくて済むこともメリットの1つだと思います!

今回はサンプルアプリケーションを作ってみます。

環境

  • Rails 5.0.4
  • ruby 2.3.3

サンプルアプリケーション作成

rails new

terminal
$ rails new ajax-ransack
$ cd ajax-ransack

Gemfile編集

Gemfileに以下を追記する

Gemfile
gem 'ransack' # 言うまでもなくransack
gem 'haml-rails'# htmlを楽に書くために使います。
gem 'faker' # ダミーデータ作成に使います。
terminal
$ bundle

UserのModelなど作成

terminal
$ rails g scaffold User name:string email:string description:text age:integer sex:string
$ rails db:migrate

適当にname,email,description,ageなどのカラムを持ったユーザーを作成します。

ダミーデータ作成

検索してなんぼですので、ダミーデータを作成します。

参考:fakerとforgeryを使ってダミーデータを生成する

seeds.rb
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
terminal
$ rails db:seed

これでそれらしきデータは入りました:sunglasses:

Controller

users_controller.rb
...

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

index.html.haml
%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とかしていく感じになるかなと。

サンプルのリンク

qiita.gif

ご指摘、真摯に受け止めますのでぜひぜひよろしくお願いします〜!

29
30
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
29
30