【Ruby on rails6】ransackを使って検索機能を作る

【Ruby on rails6】ransackを使って検索機能を作る

ransackのgithub↓

Object-based searching. . Contribute to activerecord-hackery/ransack development…
github.com

はじめに

今回はrailsのransackというgemを使用して、検索機能を作成していこうと思います。そして、この検索機能を作成する際には、これ専用の簡単なアプリケーションを使用しようと思います。

1.アプリケーションの準備をする

①アプリケーションの雛形を作る

rails new ransack

②scaffoldを使用してユーザのモデルを作成する

rails g scaffold User name:string age:integer height:integer weight:integer gender:string
rails db:migrate

※scaffoldはテンプレートとなるファイルを全て自動で作成してくれる。

③データベースに初期データを追加する

users = [
  { name: '田中ゆうこ', age: 24, height: 155, weight: 40, gender: '女' },
  { name: '山田花子', age: 19, height: 150, weight: 39, gender: '女' },
  { name: '田中太郎', age: 20, height: 160, weight: 45, gender: '男' },
  { name: '森山太郎', age: 26, height: 167, weight: 60, gender: '男' },
  { name: '山田太郎', age: 34, height: 175, weight: 74, gender: '男' },
  { name: '秋山なお', age: 18, height: 160, weight: 46, gender: '女' }
]
User.create(users)
rails db:seed

ここまででようやく準備が整いました!次からはransackについてをやっていきましょう。

2.ransackを導入する

gem 'ransack'
bundle install

ここでサーバーを起動して、localhost:3000/usersにアクセスすると、

このようなページが表示されるようになる。
このページは自分でroutesなどを書いていなかったとしてもscaffoldで自動的に作成されている。

3.検索をするためのアクションを追加する

①routesファイルの編集

Rails.application.routes.draw do
  resources :users do
    collection do
      get 'search'
    end
  end
end

検索をして、その結果を表示するためのアクションsearchを追加する。

②コントローラにsearchアクションを定義する

class UsersController < ApplicationController
  before_action :set_user, only: %i[ show edit update destroy ]

  def search
    @q = User.ransack(params[:q])
    @results = @q.result
  end

  # GET /users or /users.json
  def index
    @q = User.ransack(params[:q])
    @users = User.all
  end

  # GET /users/1 or /users/1.json
  def show
  end

  # GET /users/new
  def new
    @user = User.new
  end

  # GET /users/1/edit
  def edit
  end

  # POST /users or /users.json
  def create
    @user = User.new(user_params)

    respond_to do |format|
      if @user.save
        format.html { redirect_to user_url(@user), notice: "User was successfully created." }
        format.json { render :show, status: :created, location: @user }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /users/1 or /users/1.json
  def update
    respond_to do |format|
      if @user.update(user_params)
        format.html { redirect_to user_url(@user), notice: "User was successfully updated." }
        format.json { render :show, status: :ok, location: @user }
      else
        format.html { render :edit, status: :unprocessable_entity }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /users/1 or /users/1.json
  def destroy
    @user.destroy

    respond_to do |format|
      format.html { redirect_to users_url, notice: "User was successfully destroyed." }
      format.json { head :no_content }
    end
  end

  private

  # Use callbacks to share common setup or constraints between actions.
  def set_user
    @user = User.find(params[:id])
  end

  # Only allow a list of trusted parameters through.
  def user_params
    params.require(:user).permit(:name, :age, :height, :weight, :gender)
  end
end

ここでsearchアクションを定義し、その中でransackを使用していきます。indexの中で検索フォームを作成するため、indexの中にもransackを用いた変数を定義します。

③検索フォームの作成

次はindex.html.erbの一番下に検索フォームを作成していきます。

<h1>ユーザー検索</h1>
<%= search_form_for @q, url: search_users_path do |f| %>
  <%= f.label :name_cont, 'ユーザー名' %>
  <%= f.search_field :name_cont %>
  <br>
  <%= f.submit '検索' %>
<% end %>

ひとまずはこんな感じで作ってみます。ここで使用されているsearch_form_forはransackに標準で用意されているフォームメソッドです。form_forやform_withなどを普段のフォームで使用すると思いますが、そのransack版となっています。

search_fieldでは元々userモデルの中にあるnameに_contと記述していますが、これは部分検索をする際に使用するメソッドです。他にも_contの部分を_eqに変更すると、完全一致のものが検索できるようになるなど、さまざまなメソッドが用意されています。

④検索結果を表示するviewを作成する

フォームを作っただけだと、検索結果を表示させることができません。なので、検索結果を表示させるためのviewを作っていきます。views/usersの中にsearch.html.erbを新しく作成してその中に検索結果の出力を記述していきます。

<h1>検索結果</h1>
<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Age</th>
      <th>Height</th>
      <th>Weight</th>
      <th>Gender</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @results.each do |user| %>
      <tr>
        <td><%= user.name %></td>
        <td><%= user.age %></td>
        <td><%= user.height %></td>
        <td><%= user.weight %></td>
        <td><%= user.gender %></td>
        <td><%= link_to 'Show', user %></td>
        <td><%= link_to 'Edit', edit_user_path(user) %></td>
        <td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<%= link_to 'Top', users_path %>

このように記述をすることができたら、サーバーを起動して挙動を確認していきます。

このように検索・検索結果の出力をすることができました。

⑤フォームを書き換えてみる

<h1>ユーザー検索</h1>
<%= search_form_for @q, url: search_users_path do |f| %>
  <%= f.label :name_cont, 'ユーザー名' %>
  <%= f.search_field :name_cont %>
  <%= f.label :age, '年齢' %>
  <%= f.radio_button :age_lteq, '' %>指定しない
  <%= f.radio_button :age_lteq, '10' %>10歳以下
  <%= f.radio_button :age_lteq, '20' %>20歳以下
  <%= f.radio_button :age_lteq, '30' %>30歳以下
  <%= f.radio_button :age_lteq, '40' %>40歳以下
  <%= f.radio_button :age_gteq, '50' %>50歳以上
  <br>
  <%= f.submit '検索' %>
<% end %>

フォームの部分を書き換えてみると、名前での検索もでき、名前と年齢での検索もでき、年齢での検索もできる検索フォームを作成することができます。

4.ソート機能を作成する

このransackを使用すると、並び替えの機能も簡単に実装することができるので、そちらについても解説していきます。

①indexのカラム名を変更

      <th><%= sort_link(@q, :name, "Name") %></th>
      <th><%= sort_link(@q, :age, "Age") %></th>
      <th><%= sort_link(@q, :height, "Height") %></th>
      <th><%= sort_link(@q, :weight, "Weight") %></th>
      <th><%= sort_link(@q, :gender, "Gender") %></th>

②検索結果のカラム名を変更

      <th><%= sort_link(@q, :name, "Name") %></th>
      <th><%= sort_link(@q, :age, "Age") %></th>
      <th><%= sort_link(@q, :height, "Height") %></th>
      <th><%= sort_link(@q, :weight, "Weight") %></th>
      <th><%= sort_link(@q, :gender, "Gender") %></th>

③indexアクションを編集

今のままでは検索結果のページではソートすることが可能ですが、indexページでのソートができないので、できるようにindexアクションの@usersの部分を編集していきます。

# GET /users or /users.json
  def index
    @q = User.ransack(params[:q])
    @users = @q.result
  end

これでソート機能を実装することができました。

④ソート時の矢印を消してみる

ソートをするリンクを踏んだ際に上矢印や下矢印が出てきて、どちらのソートかわかりやすいようになってはいますが、レイアウトによってはない方がいいかもしれません。なので、この矢印を消す方法をやってみます。

       <th><%= sort_link(@q, :name, "Name", hide_indicator: true) %></th>
      <th><%= sort_link(@q, :age, "Age", hide_indicator: true) %></th>
      <th><%= sort_link(@q, :height, "Height", hide_indicator: true) %></th>
      <th><%= sort_link(@q, :weight, "Weight", hide_indicator: true) %></th>
      <th><%= sort_link(@q, :gender, "Gender", hide_indicator: true) %></th>

はい。ただhide_indicator:trueをつけただけです。超簡単!

おわり

今回はransackを使った検索機能を別のアプリケーションを作成して実装してみました。
ransackはとても便利に検索機能を実装できますね。ですけど、検索機能だけではなく、パラメータの渡し方を勉強したいみたいな人はransackを使わない方法で実装してみてからransackを実装していただくと、実装の簡単さにも驚かされますし、色々な学習にもなるかなと感じました。
最後まで読んでいただきありがとうございます!また別の記事でお会いしましょう!

カテゴリー

naska