scopeの中でifを使いつつきれいに書きたいときの案

qlog公式からのメッセージ:ログインをしていなくてもいいねを押すことができます!

railsでDBの検索クエリを書くときにscopeを利用することは多い。
scopeで、ある条件の時のみくっつけたいwhere式があるといった場合に、
コードの見通しを損なうことなく書くにはどうしたらよいか、という案をメモっておく

whereやmergeの中に三項演算子を書いてしまう案

scope :particular_user ,-> (trigger) {
  select(:user_id, :user_nm, :age)
  .where(user_nm: 'tanaka' )
  .merge( trigger ? where(user_id: '00000') : User.all ) # ココ
  .where(age: 30)
}

marge()の引数に参考演算子を書き、条件に応じてallに切り替える方法
margeにallを入れると条件として無視される

scope :particular_user ,-> (trigger) {
  select(:user_id, :user_nm, :age)
  .where( user_nm: trigger ? 'tanaka' : nil )  # ココ
  .where(age: 30)
}

where()の場合はnilを入れると条件として無視される

別のスコープにしてしまう案

scope :particular_user ,-> (trigger) {
  select(:user_id, :user_nm, :age)
  .where(user_nm: 'tanaka' )
  .admin_user_id(trigger) # ココ
  .where(age: 30)
}

# ifをこちらに移す
scope :admin_user_id ,-> (is_admin){
  return unless is_admin
  where(user_id: '00000')
}

scopeの戻り値がnilであると条件として無視される
where式を追加する条件が満たされない時はnilを返し、条件が満たされる場合はwhereを返すスコープに移す案

補足 やりたくないこと

scope :particular_user ,-> (trigger) {
  obj =  select(:user_id, :user_nm, :age).where(user_nm: 'tanaka' ).where(age: 30)

  # ココ
  # ifブロックとしてなるべく独立させたくない
  if trigger
   obj.merge( where(user_id: '00000') ) 
  end
}

こういうifブロックを別にすると、増えれば増えるほど見通しが悪くなる気がするのを回避したいという話


vranometria