2009-10-29 18 views
2

比方说,我有一个表单,用户可以搜索名称以特定name字符串开头的人,例如“Mi”会找到“Mike”和“Miguel”。我可能会创建一个查找的语句,像这样:带绑定变量和可选参数的条件

find(:all, :conditions => ['name LIKE ?', "#{name}%"]) 

假设形式也有两个可选字段,hair_coloreye_color,可用于进一步筛选结果。忽略查询的名称部分,对人的发现语句可以在可选参数任意数量的可能是这样的:

find(:all, :conditions => { params[:person] })

这对于我的两个可选参数将表现为这相当于:

find(:all, :conditions => { :hair_color => hair_color, :eye_color => eye_color })

我想不通的是如何这两种查询,其中必填字段,“名称”适用于“喜欢”条件之上,并且可选hair_coloreye_color合并PARAMET可以添加ers(也可能是其他)来进一步过滤结果。

我当然可以建立一个查询字符串来做到这一点,但我觉得必须有一个更优雅的“rails方式”。我如何将强制绑定参数与可选参数合并?

回答

4

这是命名作用域的完美使用。

在模型中创建一个名为范围:

named_scope :with_name_like, lambda {|name| 
    {:conditions => ['name LIKE ?', "#{name}%"]} 
} 

此时,您可以拨打

Model.with_name_like("Mi").find(:all, :conditions => params[:person]) 

和Rails将合并查询你。

编辑:代码克瓦:

如果名称是可选的,你可以将其省略从你的方法链中的命名范围使用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 
} 
+0

只是好奇。如果指定名称字符串也是可选的,那么如何扩展它? – Waseem 2009-10-29 08:22:29

+0

我知道必须有一个很好的干净方式来做到这一点。总是有铁轨:-)谢谢! – SingleShot 2009-10-29 15:32:38

+1

@waseem,我修改了解决方案来回答你的问题。 – EmFi 2009-10-29 16:55:59

0

要同时符合克瓦请求,但允许零而不是空白? (这是在的情况下udeful要使用 “@things = Thing.named_like(PARAMS [:名字])” 直接)

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]} : {}) } } 

我希望它能帮助