部分一致検索機能の実装をRansuckを使用せず行ったのでまとめていく。
今回は名前、メールアドレスを入力するとそれに部分一致で該当するユーザーの情報を取得できるという簡単な機能を作る。
例
名前フォームに「の」 メールアドレスフォームに「 」で検索
↓
野比 のび太 nobinobi@example.com
が出力するみたいな感じ。にしたい。
結論からということでまずはコード載せますね。
Rails.application.routes.draw do
root 'users#index'
resources :users
end
<h1>ドラえもんキャラを部分一致検索してみよう</h1>
<%= form_with(url: 'users', local: true, method: :get) do |f| %>
<span class="small">検索対象: 名前 メールアドレス</span>
<div>
<%= f.label :name, '名前' %>
<%= f.text_field :name , value: @search_params[:name] %>
</div>
<div>
<%= f.label :email, 'メールアドレス' %>
<%= f.text_field :email, value: @search_params[:email] %>
</div>
<%= f.submit '検索', class: 'btn btn-default' %>
<%end%>
<h1>検索結果</h1>
<% @users.each do |user| %>
<%= user.name %>
<%= user.email %>
<% end %>
class UsersController < ApplicationController
def index
@search_params = search_params
@users = User.search(search_params)
end
private
def search_params
params.permit( :name, :email )
end
end
class User < ApplicationRecord
scope :search, -> (search_params) do
return if search_params.blank?
name_like(search_params[:name] )
.email_like(search_params[:email])
end
scope :name_like, -> (name){where("name LIKE ?" ,"%#{name}%")}
scope :email_like, -> (email){where("email LIKE ?", "%#{email}%")}
end
ActiveRecord::Schema.define(version: 2020_10_10_011424) do
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
User.create!(name: "野比 のび太",email: "nobinobi@example.com")
User.create!(name: "剛田 武",email: "soulmate@example.com")
User.create!(name: "骨川 スネ夫",email: "kanemoti@example.com")
User.create!(name: "ドラえもん",email: "dora@example.com")
User.create!(name: "ドラミちゃん",email: "dorami@example.com")
User.create!(name: "源 しずか",email: "piano@example.com")
一個一個説明していきます。
まずviewの説明から
<h1>ドラえもんキャラを部分一致検索してみよう</h1>
<%= form_with(url: 'users', local: true, method: :get) do |f| %>
<span class="small">検索対象: 名前 メールアドレス</span>
<div>
<%= f.label :name, '名前' %>
<%= f.text_field :name , value: @search_params[:name] %>
</div>
<div>
<%= f.label :email, 'メールアドレス' %>
<%= f.text_field :email, value: @search_params[:email] %>
</div>
<%= f.submit '検索', class: 'btn btn-default' %>
<%end%>
<h1>検索結果</h1>
<% @users.each do |user| %>
<%= user.name %>
<%= user.email %>
<% end %>
まずここなのですが
<%= form_with(scope: :search ,url: 'users', local: true, method: :get) do |f| %>
検索フォームはform_withを使用しています。form_tag と form_forとの違いは下記URLにわかりやすく説明されています。
https://qiita.com/hmmrjn/items/24f3b8eade206ace17e
(以前は関連するモデルがなかったときは form_tag 関連するモデルがある時は form_forを使用していましたがrails5.1で非推奨となっています。具体例として挙げるとUser情報を使いたいだけ(検索時)などはform_tag
User情報を登録したい→登録されるデータベースが存在している時はform_forを使用していた。)
rails5.1以降より推奨されているform_withはそこら辺の処理をうまい感じに切り分けて実行してくれます。またデフォルトで非同期通信のAjaxが実装されてます。今回はJSは使用しない実装なので、リモートフォームを無効にするため local: true と指定し、HTML形式でデータをmethod: get にて通信しています。
続いてコントローラーを見ていきましょう。
class UsersController < ApplicationController
def index
@search_params = search_params
@users = User.search(search_params)
end
private
def search_params
params.permit( :name, :email )
end
end
ここでのみそは User.search(search_params) です。こちらのsearchメソッドなのですがUsermodelの方に部分一致検索機能をscopeしています。送られた値に対しsearchでnameとemailに部分一致処理をし返します。続いてmodelを参照してください。
class User < ApplicationRecord
scope :search, -> (search_params) do
return if search_params.blank?
name_like(search_params[:name] )
.email_like(search_params[:email])
end
scope :name_like, -> (name){where("name LIKE ?" ,"%#{name}%")}
scope :email_like, -> (email){where("email LIKE ?", "%#{email}%")}
end
searchスコープはこちらに飛んで一つ一つ部分処理をした後コントローラに返されます。
return if search_params.blank?
を入れておく事で仮に何も値がはいっていなくても処理をそこで止めてコントローラに返します。
検索対象が今回のように:name :emailと複数である場合はparamsを繰り返し処理とし一つ一つ検索を返すようにします。
今回は以上となります。
もしここは違うなどありましたどんどん指摘しください。