もた日記

くだらないことを真面目にやる

Railsメモ(11) : Ransackで検索機能を追加する

github.com

Railsで検索機能を追加するにはRansackを使用するのがよいらしいので試してみる。
Gemfileに下記行を追加してbundle installする。

gem 'ransack'

まずコントローラのapp/controllers/songs_controller.rbを編集する。

class SongsController < ApplicationController
  def index
    @q = Song.ransack(params[:q])
    @songs = @q.result.page(params[:page])
  end
end


続いて検索用のフォームを追加するためにビューのファイルを編集するが、今回はNavbarに追加してみるのでapp/vies/layouts/application.html.erbを編集する。
試しにtitleカラムとdisplay_artistカラムに対して文字列を含むレコードを検索するフォームを追加してみる。文字列を含むはcontなので、titleカラムに対して検索する場合はtitle_contのようになる。

 …
<div class="navbar navbar-default navbar-fixed-top">
  <div class="container">
    <div class="navbar-header">
      <%= link_to 'Billboard', root_path, class: 'navbar-brand' %>
    </div>
    <%= search_form_for @q, html: { class: 'navbar-form navbar-left' } do |f| %>
      <div class="form-group">
        <%= f.search_field :title_cont, class: 'form-control', placeholder: 'title' %>
      </div>
      <div class="form-group">
        <%= f.search_field :display_artist_cont, class: 'form-control', placeholder: 'display_artist' %>
      </div>
      <%= f.submit class: 'btn btn-default' %>
    <% end %>
  </div>
</div>
 …

編集後アクセスしてみるが下記エラーが発生。どうやら名前付きルートがないことが原因らしいのでconfig/routes.rbを編集する。

ActionView::Template::Error (undefined method `songs_path' for #<#<Class:0x007f4021f537d8>:0x007f4021f52ae0>):
 …
# get 'songs/index' # 編集前
match '/songs',  to: 'songs#index', via: 'get'
 …

再度アクセスすると図のように検索フォームが表示され、

f:id:wonder-wall:20150809140729p:plain

例えば、titleカラムに"happy"という文字列を含むレコードを正しく検索できている。

f:id:wonder-wall:20150809140739p:plain

Ransackの検索条件


基本的な検索条件の書き方は下記ページに書いてあるが、以下の条件が指定できる。

Basic Searching · activerecord-hackery/ransack Wiki · GitHub

  • eq (equals)
  • matches
  • lt (less than)
  • lteq (less than or equal to)
  • in
  • cont
  • cont_any (contains any)
  • start (starts with)
  • end (ends with)
  • true
  • false
  • present
  • null

また、複数のカラムを組み合わせたい場合は以下のようにandorでつなぐ。

<%= f.search_field :title_and_display_artist_cont, class: 'form-control', placeholder: 'title' %>
<%= f.search_field :title_or_display_artist_cont, class: 'form-control', placeholder: 'title' %>

検索可能なカラムを指定


特に何も指定しないと以下のように全てのカラムが検索可能になってしまい、クエリパラメータを直接書き換えれば検索ができてしまう。
これは意図しない不具合を引き起こすかもしれないのでransackable_attributesを使用して検索可能なカラムを指定する。

[1] pry(main)> Song.ransackable_attributes
[
    [0] "id",
    [1] "title",
    [2] "display_artist",
    [3] "ranking",
    [4] "year",
    [5] "created_at",
    [6] "updated_at"
]
class Song < ActiveRecord::Base
  def self.ransackable_attributes(auth_object = nil)
    %w(title display_artist)
  end
end
[1] pry(main)> Song.ransackable_attributes
[
    [0] "title",
    [1] "display_artist"
]

パーフェクト Ruby on Rails

パーフェクト Ruby on Rails