假设我有一个表单,用户可以搜索名称以特定name
字符串开头的人,例如,“Mi”会找到“Mike”和“Miguel”。我可能会像这样创建一个find语句:
find(:all, :conditions => ['name LIKE ?', "#{name}%"])
我们假设该表单还有两个可选字段hair_color
和eye_color
,可用于进一步过滤结果。忽略查询的名称部分,可以接受任意数量的可选参数的人的查找语句可能如下所示:
find(:all, :conditions => { params[:person] })
对于我的两个可选参数,其行为与此相同:
find(:all, :conditions => { :hair_color => hair_color, :eye_color => eye_color })
我无法弄清楚如何合并这两种查询,其中必填字段“name”应用于上述“like”条件,以及可选hair_color
和{{1}可以添加参数(可能还有其他参数)以进一步过滤结果。
我当然可以建立一个查询字符串来做到这一点,但我觉得必须有一个更优雅的“轨道方式”。如何将强制绑定参数与可选参数合并?
答案 0 :(得分:4)
这是对命名范围的完美使用。
在模型中创建命名范围:
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
}
答案 1 :(得分:0)
还要遵守Waseem请求,但允许nil为空白? (如果您想直接使用“@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]} : {}) } }
我希望它有所帮助