LoginSignup
1
0

More than 1 year has passed since last update.

Rails6.1版 Relation配列指定でORクエリーを作る拡張

Last updated at Posted at 2021-08-30

目的

Railsデフォルトのorだと、何らかの動的な仕様の都合でRelation条件配列として保持している場合、ORを適用するのが大変

first_condition = or_conditions.shift
or_conditions.inject(first_scope) do |merged_scope, scope|
  merged_scope.or(scope)
end

理想

このような形でサクッとORクエリーを作りたい

User.where.or(*or_conditions)

実装

Rails5版 OR クエリ構築するマン のRails6.1版(merge! → and!)

Rails6.1からmergeが厳密になり、統合方法の指定が必要になり汎用拡張には使えなくなった、そのため条件の追加である and! を使ってRelationにOR条件を追加する

# initialize/query_methods.rb 等で拡張する
ActiveRecord::QueryMethods::WhereChain.include(Module.new do
  def or(first_scope, *scopes)
    or_scope = scopes.inject(first_scope) do |relation, scope|
      relation.or(scope)
    end

    @scope.and!(or_scope)
    @scope
  end
end)

結果

or_conditions = [User.where(id: 2), User.where(id: 3)]
User.where(id: 1).where.or(*or_conditions).where(id: 4).to_sql
=> "SELECT `users`.* FROM `users` 
    WHERE `users`.`id` = 1 AND (`users`.`id` = 2 OR `users`.`id` = 3) AND `users`.`id` = 4"

補足

and!なので本体とOR条件のjoins条件が不一致だとエラーになります

デフォルトのOR挙動と同じなので特に問題ではありませんが、もし既にRails5版 OR クエリ構築するマン を利用されているものをRails6.1に上げる際にはjoinsを揃える訂正が必要になる可能性があります(不一致だとエラーが発生します)

参考

1
0
3

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
0