- 更新日: 2017年03月22日
- 公開日: 2016年02月16日
作って学ぶRuby on Rails Vol.21 検索機能を盛り込もう!
検索機能の実装
前項までに、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を記述しないようにしましょう。
ブラウザで確認すると下の図のようになります。
続いて、検索条件に応じた処理を実装していきます。
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
それでは、実際にブラウザで確認してみましょう。
※絞り込み実施前
※絞り込み実施後
※性別による絞り込み実施後
Try 出身地による絞り込みを追加しよう ①本項で学習したことを生かし、出身地による絞り込み機能を追加してみましょう。 ②ユーザー一覧ページに、ユーザー登録画面へのリンクを作成してみましょう。 |
NEXT LESSON ☛ gemを使おう!
PREV LESSON ☛ 削除機能を実装しよう!
目次 - Ruby & Ruby on Rails テキスト目次 -
- この記事を書いた人
- CodeCampus編集部