作って学ぶRuby on Rails Vol.21 検索機能を盛り込もう!



作って学ぶRuby on Rails Vol.21 検索機能を盛り込もう!
目次
  1. 検索機能の実装
  2. ユーザー名による絞り込み
  3. 性別による絞り込み

検索機能の実装

前項までに、Modelを利用したCRUDの実装を行いました。

  • ユーザー一覧ページ
  • ユーザーの詳細情報ページ
  • ユーザー登録ページ
  • ユーザー情報編集ページ

上記4つのページを作成してきましたが、今回はユーザー一覧ページに、ユーザーを検索する機能を追加します。

ユーザーの検索には下記の機能を実装します。

  • ユーザー名による検索
  • 性別による検索

仕様としては、ユーザー名はテキスト形式で記入し、部分一致検索(完全一致ではない)で行い、性別はプルダウンによる選択形式で行うようにします。

実装の前に下記のURLからユーザー情報を10名分ほど登録しておくと、以後作業しやすくなります。

http://xxxxx.c9users.io:8080/users/new

※xxxxxの部分は環境により異なります。

それでは検索フォームを実装していきますので、app/views/users/index.html.erbを開き、下記のコードを追記して下さい。

※現時点ではCSSは意識しません

<div>
<%= form_tag(users_path, method: "get") do %>
<%= label_tag :name, "名前" %><%= text_field_tag :name, params[:name] %>
<%= label_tag :name, "性別" %>
<%= select_tag :gender, options_for_select(User.genders), include_blank: true %>
<%= submit_tag "検索" %>
<% end %>
</div>

以前、ユーザーの登録や編集の際に、form_forメソッドを使用してフォームを作成しましたが、今回はform_tagメソッドを使用してフォームを作成します。

form_forとform_tagの使い分けとしては、form_forはModelに基づく場合に使用します(主に更新や新規作成の場合)。form_tagはModelに基づかない場合に使用します(主に検索)。

users_pathと指定しているので検索ボタンを押下し、サーバーへリクエストした際にはindexというActionが実行されることになります。

label_tagメソッドは、その名の通り入力欄にラベルを付けるために使用します。

性別の検索は選択形式で行いたいので、今回はselect_tagメソッドを使用してセレクトボックス作成します。

select_tagメソッドの使用方法は少しややこしいです。

第1引数はname属性を表し、第2引数でoptions_for_selectメソッドを使用することで、選択する内容を指定します。

User.gendersというのはUserというModelに定義されたgenderというenum(列挙型)のキーと値を全て配列で取得するという内容です。

enumの値を全て取得する場合は、定義したenum名の複数形にします。今回の例だと、genderというenum名なのでgendersになります。


class User < ActiveRecord::Base
  enum gender: { unknown: 0, male: 1, female: 2, other: 9 }
end

上記のコードが現状のUserというModelの状態ですが、genderという名前のついたenumが定義されているのがわかります。

つまり、User.gendersと記述することで、unknown,male,female,otherとそれぞれの値が取得できます。

また、include_blankをtrueと指定することで初期値がブランクになります。

今回は、検索をする際に性別で絞らないケースが考えられるのでブランク値を許容する形にします。

逆に、性別の入力を必須にしたい場合はinclude_blankをfalseにする、もしくはinclude_blankを記述しないようにしましょう。

ブラウザで確認すると下の図のようになります。

Ruby_on_Rails_検索1

続いて、検索条件に応じた処理を実装していきます。

app/models/user.rbを開いてください。


class User < ActiveRecord::Base
  enum gender: { unknown: 0, male: 1, female: 2, other: 9 }
end

現状、上記の記述になっています。

今回、ユーザーの検索(絞り込み)を行うので、下記のコードを記述します。

#ユーザー名による絞り込み
scope :get_by_name, ->(name) {
where("name like ?", "%#{name}%")
}
#性別による絞り込み
scope :get_by_gender, ->(gender) {
where(gender: gender)
}

上記コードの意味としては、コメントでも記述していますが、絞り込みを行う処理になります。

これらはメソッドではなく、Ruby on RailsのModelの機能である、scopeというものです。

scopeは少し見慣れない書き方をしますが、get_by_nameやget_by_genderがscope名で、nameやgenderが引数です。{}括弧の中が処理に当たる部分なのですが、whereメソッドを使用してnameまたはgenderで絞り込みを行っています。

get_by_nameの方では、namelike?としていますが、likeはあいまい検索(部分一致検索)を表しており、?の部分は、第2引数により置換されます。

つまり、フォームに田中と入力されていた場合、namelike‘%田中%’となります。%の部分については下記の表を参照して下さい。

like検索の%について

田中さん、中田さん、野中さん、植田さんの4名を対象として行った場合

指定 検索内容 検索結果
name = ‘田中さん’ 完全一致 田中さん
name like ‘%中%’ 部分一致 田中さん

中田さん

野中さん

name like ‘中%’ 前方一致 中野さん
name like ‘%さん’ 後方一致 田中さん

中田さん

野中さん

植田さん

2つのscopeをapp/models/user.rbに追記すると下記になります。


class User < ActiveRecord::Base
enum gender: { unknown: 0, male: 1, female: 2, other: 9 }

# ユーザー名による絞り込み
scope :get_by_name, ->(name) {
where("name like ?", "%#{name}%")
}
# 性別による絞り込み
scope :get_by_gender, ->(gender) {
where(gender: gender)
}
end

最後に、Actionを修正します。

app/controllers/users_controller.rbを開いて下さい。indexというActionに下記の内容を追記することで、入力フォームからの検索を行うことができるようになります。

if params[:name].present?
@users = @users.get_by_name params[:name]
end
if params[:gender].present?
@users = @users.get_by_gender params[:gender]
end

内容としては、ユーザー名をパラメータとして受け取っている際は、UserというModelのget_by_nameというscopeを使用して絞り込みを行い、性別をパラメータとして受け取っている場合はget_by_genderというscopeによって絞り込みが行われます。

ユーザー名と性別の両方を受け取っている場合は両方のscopeを使用します。

どちらも受け取っていない場合は、当然絞り込みは行われません。

追記後のapp/controllers/users_controller.rbは下記のコードです。


class UsersController < ApplicationController
  # 初期表示
  def index
  @users = User.all
  # パラメータとして名前か性別を受け取っている場合は絞って検索する
  if params[:name].present?
  @users = @users.get_by_name params[:name]
  end
  if params[:gender].present?
  @users = @users.get_by_gender params[:gender]
  end
  end
  # データを閲覧する画面を表示するためのAction
  def show
  @user = User.find(params[:id])
  end
  # データを作成する画面を表示するためのAction
  def new
  @user = User.new
  end
  # データを更新する画面を表示するためのAction
  def edit
  @user = User.find(params[:id])
  end
  # データを作成するためのAction
  def create
  @user = User.new(user_params)
  @user.save
  redirect_to @user
  end
  # データを更新するためのAction
  def update
  @user = User.find(params[:id])
  @user.update_attributes(user_params)
  redirect_to @user
  end
  # データを削除するためのAction
  def destroy
  @user = User.find(params[:id])
  @user.destroy
  redirect_to users_path
  end

  def user_params
  params.require(:user).permit(:name, :gender, :birthday, :hometown, :remarks)
  end
 end

それでは、実際にブラウザで確認してみましょう。

Ruby_on_Rails_view_検索2

※絞り込み実施前

Ruby_on_Rails_view_検索3

※絞り込み実施後

Ruby_on_Rails_view_検索4

※性別による絞り込み実施後

Try 出身地による絞り込みを追加しよう ①本項で学習したことを生かし、出身地による絞り込み機能を追加してみましょう。 ②ユーザー一覧ページに、ユーザー登録画面へのリンクを作成してみましょう。

 

NEXT LESSON ☛ gemを使おう!

PREV LESSON ☛ 削除機能を実装しよう!

目次 - Ruby & Ruby on Rails テキスト目次 -

関連記事

CodeCampus編集部
この記事を書いた人
CodeCampus編集部
\ 無料体験開催中!/自分のペースで確実に習得!
オンライン・プログラミングレッスンNo.1のCodeCamp