LoginSignup
1
2

More than 3 years have passed since last update.

モデルによらないあいまい検索をrailsで実装

Last updated at Posted at 2019-08-14

概要

  • Userモデルのnameカラムで検索したい
  • Userモデルのemailカラムで検索したい
  • Bookモデルのtitleカラムで検索したい

といったように、同じモデルの異なるカラムや、そもそも異なるモデルのカラムに対して、名称検索をかけたくなることはよくあると思います。
そこで使える手法を整理します。

動作環境

Rails 4.2.11.1
ruby 2.4.5p335 (2018-10-18 revision 65137) [x86_64-darwin16]

愚直に実装する

必要な場所で、必要な数だけ scope を生やします。

user.rb
class User < ActiveRecord::Base
  scope :name_like, -> (value) {
    pattern = ActiveRecord::Base.send(:sanitize_sql_like, value)
    where('name LIKE ?', "%#{pattern}%")
  }

  scope :email_like, -> (value) {
    pattern = ActiveRecord::Base.send(:sanitize_sql_like, value)
    where('email LIKE ?', "%#{pattern}%")
  }
end
book.rb
class Book < ActiveRecord::Base
 scope :title_like, -> (value) {
   pattern = ActiveRecord::Base.send(:sanitize_sql_like, value)
   where('title LIKE ?', "%#{pattern}%")
end

module化する

例えば上の実装では value が nil や空文字の場合に検索結果がなくなってしまいますが、
そのような場合には何もフィルタリングしない、という仕様変更があったとします。

愚直な実装では、あいまい検索を行いたいモデルの全てで検索ロジックを実装していますから、
検索方法に変更が必要になってしまったことを想像すると・・・気が引けますね。

そこで、検索ロジック部分を module として切り離します。

fuzzy_match_searchable.rb
module FuzzyMatchSearchable
  extend ActiveSupport::Concern

  class_methods do
    def fuzzy_match(column, value)
      return current_scope if value.blank?

      pattern = ActiveRecord::Base.send(:sanitize_sql_like, value)
      where(%("#{table_name}"."#{column}" LIKE ?), "%#{pattern}%")
    end
  end
end

各モデルでは、以下のように実装します。

user.rb
class User < ActiveRecord::Base
  include FuzzyMatchSearchable

  scope :name_like, (value) -> { fuzzy_match('name', value) }
  scope :email_like, (value) -> { fuzzy_match('email', value) }
end
book.rb
class Book < ActiveRecord::Base
  include FuzzyMatchSearchable

  scope :title_like, (value) -> { fuzzy_match('title', value) }
end

コードクローンを回避でき、とってもいい感じですね。

参考記事

[Rails] ActiveSupport::Concern の存在理由:https://qiita.com/castaneai/items/6dc121ce6ff100614f42
sanitize_sql_like について:https://apidock.com/rails/v4.2.1/ActiveRecord/Sanitization/ClassMethods/sanitize_sql_like

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2