LoginSignup
25
18

More than 5 years have passed since last update.

ActiveRecordに特定条件の時だけ有効になるwhere文を追加する

Posted at

導入

controllerとかで稀によくある特定条件の場合だけ条件式を追加する処理が見た目悪くてなんとかしたかった。
※ 検索とかそんな時に比較的よく見かける

(例)検索条件に"今日"が入ってきた時には「作成日が今日」を検索する

@items = User.where(public_flag: true)
@items = @items.where(created_at: Date.today) if params[:filter] == "今日"

(例)名前が入力されたらその名前のユーザを返す。入力が空なら全件返す

@items = params[:name].present? ? User.where(name: params[:name]) : User.all 

何とかする

rails4から where.not(id: 1) みたいな書き方で1行でいい感じに完結する書き方を模索

where.if の実装

where.if(true/false, query) で 第1引数に booleanを渡してtrueならqueryを実行、falseなら不採用を実現する。

User.where.if(false, id: 1).to_sql
=> "SELECT `users`.* FROM `users`"
User.where.if(true, id: 1).to_sql
=> "SELECT `users`.* FROM `users` WHERE `users`.`id` = 1"

拡張

ActiveRecord::QueryMethods::WhereChain.include(Module.new do
  def if(condition, opts, *rest)
    return @scope unless condition
    @scope.where_values += @scope.send(:build_where, opts, rest)
    @scope
  end
end)

## 書き直す

(例)検索条件に"今日"が入ってきた時には「作成日が今日」を検索する

@items = User.where(public_flag: true).where.if(params[:filter] == "今日", created_at: Date.today) 

(例)名前が入力されたらその名前のユーザを返す。入力が空なら全件返す

@items = User.where.if(params[:name].present?, name: params[:name]) 

参考

Rails 4.2 で Arel を使って OR クエリを構築する
http://qiita.com/QUANON/items/d6772127ffc0e7b78759

25
18
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
25
18