Railsで複数ワードでAND検索やOR検索を実装する
背景
- AND検索やOR検索をしたい
サンプルリポジトリ
こちらから、実装済みソースコードが見られます。
注意
サンプルのリポジトリは、Dockerで起動することを前提に作成されています。
Dockerを使用しない場合は、appフォルダ以下で通常のrailsの起動処理を行ってください。
なお、記事ではDockerを使用せず導入する手順で記載していますのでご注意ください。
Rails6で記述していますが、Rails5でも同様に動作すると思います。
ソースコードのコメントについて
基本的にコメントを多めに記載しています。こちらを参考に実装して、ロジックの理解を深めてください。
Seedファイルにユーザーの初期情報が入っています。データ登録画面は、今回は省略していますのでSeedでご利用ください
実装
今回、seedには、Fakerを使うのでseedを使用する場合は、適宜追加してください
group :development, :test do
# Faker
gem 'faker'
end
rails g controller homes index
rails g model post
class CreatePosts < ActiveRecord::Migration[6.1]
def change
create_table :posts do |t|
t.string :title
t.text :body
t.timestamps
end
end
end
# This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup).
#
# Examples:
#
# movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }])
# Character.create(name: 'Luke', movie: movies.first)
100.times.each do |tmp|
Post.create([
title: Faker::JapaneseMedia::StudioGhibli.movie,
body: Faker::JapaneseMedia::StudioGhibli.quote
])
end
rails db:seed
class HomesController < ApplicationController
def index; end
def search
# splitで正規表現を使ってキーワードを空白(全角・半角・連続)分割する
# 連続した空白も除去するので、最後の“+”がポイント
@keywords = params[:keywords].split(/[[:blank:]]+/)
# 検索タイプ取得
# AND : AND検索 / OR : OR検索
@type = params[:type]
# 空のモデルオブジェクト作成(何も入っていない空配列のようなもの)
@results = Post.none
# タイプ別で検索実行
if @type == 'AND'
# -----------
# AND検索
# -----------
@keywords.each_with_index do |keyword, i|
# 1回目のループでは、1つ目のワードで検索
# 結果を@resultsに詰め込む
@results = Post.search(keyword) if i == 0
# 2回目以降のループでは、1回目の結果を更にモデル定義の検索メソッドで絞り込みしていく
# 結果を@resultsに詰め込む
@results = @results.merge(@results.search(keyword))
end
else
# -----------
# OR検索
# -----------
@keywords.each do |keyword|
# 単純にモデル定義の検索メソッドにデータを渡す。
# 検索ワードの数だけor検索を行う
# 結果を@resultsに詰め込む
@results = @results.or(Post.search(keyword))
end
end
render :index
end
end
class Post < ApplicationRecord
def self.search(keyword)
# あいまい検索
# “?”に対してkeywordが順番に入る
# LIKEは、あいまい検索の意味で、“%”は、前後のあいまいという意味
# “#{keyword}”は、Rubyの式展開
where('title LIKE ? OR body LIKE ?', "%#{keyword}%", "%#{keyword}%")
end
end
<h1>Homes#index</h1>
<p>Find me in app/views/homes/index.html.erb</p>
<%= form_tag(search_path, method: :get) do %>
<%= label_tag :keywords, '検索ワード' %>
<%# 検索ワードを引く次ぐためにparams[:keywords] %>
<%= text_field_tag :keywords, params[:keywords] %>
<%# セレクトボックスの状態を引き継ぐためにoptions_for_selectのselectedオプションを使用 %>
<%= select_tag('type', options_for_select([%w[AND AND], %w[OR OR]], { :selected => params[:type] })) %>
<%= submit_tag '検索' %>
<% end %>
<%# @resultsにデータが入っていれば検索結果を表示する %>
<% if @results %>
<h2><%= @keywords %> Search Result ( <%= @type %> )--></h2>
<% @results.each do |result| %>
<p>
<%= result.title %><br>
<small>
<%= result.body %>
</small>
</p>
<% end %>
<% end %>
最後に
以上で、実装は完了のはずです。うまく動かない場合は、サンプルリポジトリを確認してください。