LoginSignup
7
3

More than 5 years have passed since last update.

yield_selfを使い、ある特定の条件の時だけwhere句を有効にした話

Last updated at Posted at 2018-12-24

コーディング中に、特定の条件の時だけwhere句を有効にしたい!と思うことがありました。
最初は単純にif文で分岐していたのですが、あまりにもダサいと思ったので奮闘してみました。

サンプルコード
if kind == 'hoge'
   User.where(kind: kind)
else
   User.all
end

ActiveRecordを拡張

こちらの記事を参考に、ActiveRecordを拡張してみました。
記事内の拡張コードはRails5では動かなかったので、Railsのコードを読みつつ以下のように拡張しました。

拡張コード
ActiveRecord::QueryMethods::WhereChain.include(Module.new do
  def if(condition, opts, *rest)
    return @scope unless condition

    @scope.where_clause += @scope.send(:where_clause_factory).build(opts, rest)
    @scope
  end
end)
サンプルコード
kind = 'hoge'
User.where.if(kind == 'hoge', kind: kind).to_sql
=> "SELECT `users`.* FROM `users` WHERE `users`.`kind` = hoge"
kind = 'fuga'
User.where.if(kind == 'hoge', kind: kind).to_sql
=> "SELECT `users`.* FROM `users`"

いい感じですね :tada:

レビューで却下される

ドヤ顔でプルリクを送るもレビューで以下の指摘を受けました。

  • Railsのバージョンが上がった時このコードが動く保証がない
    • 現にRails4の拡張コードがRails5で動かなかった
  • Rails標準機能でないため、初めてこのコードを見た人が戸惑うのではないか
    • 驚き最小の原則は重要

ごもっとも。。。としか言えなかったので拡張コードの採用は見送りました。

yield_selfを使う

もうif文で書くかと諦めかけていたところ、yield_selfを使ってはどうかと助言をいただきました。
yield_selfを使ったコードがこちら。

サンプルコード
kind = 'hoge'
User.yield_self{|scope| kind == 'hoge' ? scope.where(kind: kind) : scope.all }.to_sql
=> "SELECT `users`.* FROM `users` WHERE `users`.`kind` = hoge"
kind = 'fuga'
User.yield_self{|scope| kind == 'hoge' ? scope.where(kind: kind) : scope.all }.to_sql
=> "SELECT `users`.* FROM `users`"

以下のようにQueryMethodを繋げることもできます。

サンプルコード
kind = 'hoge'
User.yield_self{|scope| kind == 'hoge' ? scope.where(kind: kind) : scope }.where(age: 0..10).to_sql
=> "SELECT `users`.* FROM `users` WHERE `users`.`kind` = hoge AND (`users`.`age` BETWEEN 0 AND 10)"
kind = 'fuga'
User.yield_self{|scope| kind == 'hoge' ? scope.where(kind: kind) : scope }.where(age: 0..10).to_sql
=> "SELECT `users`.* FROM `users` WHERE (`users`.`age` BETWEEN 0 AND 10)"

yield_selfを使ったコードは無事LGTMしていただきました :tada:

まとめ

  • yield_self便利
  • チーム開発で拡張は控えた方が無難かも
7
3
1

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
7
3