具有绑定变量和可选参数的条件

时间:2009-10-29 07:25:57

标签: ruby-on-rails activerecord find

假设我有一个表单,用户可以搜索名称以特定name字符串开头的人,例如,“Mi”会找到“Mike”和“Miguel”。我可能会像这样创建一个find语句:

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 })

我无法弄清楚如何合并这两种查询,其中必填字段“name”应用于上述“like”条件,以及可选hair_color和{{1}可以添加参数(可能还有其他参数)以进一步过滤结果。

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

2 个答案:

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

我希望它有所帮助