バインド変数とオプションのパラメーターを使用した条件
-
10-07-2019 - |
質問
たとえば、「Mi」などの特定の name
文字列で始まる名前のユーザーを検索できるフォームがあるとします。 "マイク"および「ミゲル」。私はおそらく次のような検索ステートメントを作成します:
find(:all, :conditions => ['name LIKE ?', "#{name}%"])
フォームに2つのオプションフィールド hair_color
と eye_color
があり、これらを使用して結果をさらにフィルタリングできるとします。クエリの名前部分を無視すると、任意の数のオプションパラメータを受け取ることができる人の検索ステートメントは次のようになります。
find(:all、:conditions => {params [:person]})
2つのオプションパラメータのうち、これと同等の動作をするものはどれですか:
find(:all、:conditions => {:hair_color => hair_color、:eye_color => eye_color})
私が理解できないのは、これらの2種類のクエリをマージする方法です。 「like」に適用されます上記の条件、およびオプションの hair_color
および eye_color
パラメーター(およびその他のパラメーター)を追加して、結果をさらにフィルター処理できます。
確かにこれを行うためにクエリ文字列を作成できますが、「レールの方法」が必要だと感じています。それはよりエレガントです。必須のバインドパラメーターをオプションのパラメーターとマージするにはどうすればよいですか?
解決
これは、名前付きスコープの完全な使用法です。
モデルに名前付きスコープを作成します:
named_scope :with_name_like, lambda {|name|
{:conditions => ['name LIKE ?', "#{name}%"]}
}
この時点で電話をかけることができます
Model.with_name_like("Mi").find(:all, :conditions => params[:person])
そしてRailsはクエリをマージします。
編集:Waseemのコード:
名前がオプションの場合、if条件を使用してメソッドチェーンから名前付きスコープを省略することができます。
unless name.blank?
Model.with_name_like("Mi").find(:all, :conditions => params[:person])
else
Model.find(:all, :conditions => params[:person])
end
または名前付きスコープを再定義して同じことを行うこともできます。
named_scope :with_name_like, lambda {|name|
if name.blank?
{}
else
{:conditions => ['name LIKE ?', "#{name}%"]}
end
}
更新
最後のコードスニペットのRails 3バージョンは次のとおりです。
scope :with_name_like, lambda {|name|
if not name.blank?
where('name LIKE ?', "#{name}%")
end
}
他のヒント
Waseemリクエストにも準拠しますが、代わりに空白を許可しますか? (" @things = Thing.named_like(params [:name])"を直接使用したい場合には、これはおかしいです)
named_scope :named_like, lambda do |*args|
if (name=args.first)
{:conditions => ["name like ?",name]}
else
{}
end
end
# or oneliner version:
named_scope :named_like, lambda{|*args| (name=args.first ? {:conditions => ["name like ?",name]} : {}) } }
お役に立てばと思います