假设我有一个表单,用户可以搜索名称以特定name字符串开头的人,例如<!>“Mi <!>”;会找到<!>“迈克<!>”;和<!>“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 })

我无法弄清楚如何合并这两种查询所需的字段,<!> quot; name <!> quot;应用于<!> quot; like <!> quot;上面的条件,可以添加可选的<=>和<=>参数(可能还有其他参数)来进一步过滤结果。

我当然可以建立一个查询字符串来执行此操作,但我觉得必须有一个<!> quot; rails way <!> quot;那更优雅。如何将强制绑定参数与可选参数合并?

有帮助吗?

解决方案

这是对命名范围的完美使用。

在模型中创建命名范围:

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请求,但允许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]} : {}) } }

我希望它有所帮助

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top