Created
December 10, 2015 06:02
-
-
Save pinzolo/3ec384302b0539446281 to your computer and use it in GitHub Desktop.
Arel を使って複数テーブルから or 検索
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# こんなテーブルがあるとします | |
create_table :users do |t| | |
t.string :name | |
t.string :email | |
end | |
create_table :belongings do |t| | |
t.integer :user_id | |
t.string :company_name | |
t.string :dept_name | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 1つのキーワードであらゆる属性をあいまい検索したい場合、Arelを使えばこう書けます | |
# left join も Arel で書けますが、冗長なので eager_load で代用してます | |
match_key = "%#{keyword}%" | |
name_matches = User.arel_table[:name].matches(match_key) | |
email_matches = User.arel_table[:email].matches(match_key) | |
company_name_matches = Belonging.arel_table[:company_name].matches(match_key) | |
dept_name_matches = Belonging.arel_table[:dept_name].matches(match_key) | |
User.eager_load(:belonging).where(name_matches.or(email_matches).or(company_name_matches).or(dept_name_matches)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# or のメソッドチェーンがなんかやだね。こうすれば対応カラムが増えた時 matchers の要素を増やすだけで済むぞ | |
match_key = "%#{keyword}%" | |
matchers = [User.arel_table[:name].matches(match_key), | |
User.arel_table[:email].matches(match_key), | |
Belonging.arel_table[:company_name].matches(match_key), | |
Belonging.arel_table[:dept_name].matches(match_key)] | |
condition = matchers.inject { |cond, matcher| cond.or(matcher) } | |
User.eager_load(:belonging).where(condition) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# これならシンプルに inject(&:sym) でいけるね | |
match_key = "%#{keyword}%" | |
matchers = [User.arel_table[:name].matches(match_key), | |
User.arel_table[:email].matches(match_key), | |
Belonging.arel_table[:company_name].matches(match_key), | |
Belonging.arel_table[:dept_name].matches(match_key)] | |
User.eager_load(:belonging).where(matchers.inject(&:or)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# matchers も定型的なので冗長だよね | |
class_columns_set = { User => [:name, :email], Belonging => [:company_name, :dept_name] } | |
matchers = class_columns_set.map do |cls, cols| | |
cols.map { |col| cls.arel_table[col].matches("%#{keyword}%") } | |
end.flatten | |
User.eager_load(:belonging).where(matchers.inject(&:or)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# なんかシンプルなパターンなら切り出せそう | |
class SimpleFinder | |
def initialize(base_class, class_columns_set) | |
@base_class = base_class | |
@class_columns_set = class_columns_set | |
end | |
def find(keyword) | |
matchers = @class_columns_set.map do |cls, cols| | |
cols.map { |col| cls.arel_table[col].matches("%#{keyword}%") } | |
end.flatten | |
foreign_tables = @class_columns_set.keys.reject { |cls| cls == @base_class }.map(&:table_name) | |
@base_class.eager_load(*foreign_tables).where(matchers.inject(&:or)) | |
end | |
end | |
SimpleFinder.new(User, User => [:name, :email], Belonging => [:company_name, :dept_name]).find('foobar') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment