ActiveRecord查找开始

真的很简单的问题 – 我如何做一个search查找名称以ActiveRecord中的某个string开始的所有logging。 我已经在互联网上看到了各种各样的字节,使用了逐字的LIKE SQL子句 – 但是从我听说的不是“正确”的方式。

有没有适当的Rails方法?

我强烈推荐使用Searchlogic插件。

然后就像:

@search = Model.new_search(params[:search]) @search.condition.field_starts_with = "prefix" @models = @search.all 

Searchlogic非常聪明,就像ActiveRecord一样,在starts_with条件下select字段名称。 它也将处理所有的分页。

这种方法将有助于防止SQL注入,也将是数据库不可知的。 Searchlogic最终会根据您使用的数据库适配器以不同方式处理search。 你也不必写任何SQL!

Searchlogic有很好的文档,很容易使用(我自己是Ruby和Rails的新手)。 当我被困住了,插件的作者甚至在几个小时内回答了一个直接的电子邮件,帮助我解决了我的问题。 我不能推荐Searchlogic足够…你可以告诉。

如果你正在寻找在数据库中search,那么你需要使用SQL。

当然,您需要在数据库中进行search,否则您需要将所有对象加载到Ruby中(这不是件好事)。

所以,你需要类似的东西

 MyModel.find(:all, :conditions => ["field LIKE ?", "#{prefix}%"]) 

其中prefix是您正在寻找的string的variables。

在Rails 3.0+中,这成为:

 MyModel.where("field LIKE :prefix", prefix: "#{prefix}%") 

免责声明:我是Ruby和Rails的新手,我仍然试图学习Ruby的方式来做事,但是我一直在编写我一生中超过一半的时间,并在专业领域工作了十年。 DRY是一个我非常熟悉的概念。 这是我如何实现它。 这与纳尔斯克的回答非常相似,我认为这也是好的。

 # name_searchable.rb # mix this into your class using # extend NameSearchable module NameSearchable def search_by_prefix (prefix) self.where("lower(name) LIKE '#{prefix.downcase}%'") end end 

然后在你的模型中:

 class User < ActiveRecord::Base extend NameSearchable ... end 

然后当你想使用它:

 User.search_by_prefix('John') #or User.search_by_prefix("#{name_str}") 

有一件事要注意:

传统的关系型数据库在满足这种查询方面并不是非常好的。 如果你正在寻找一个高度响应的实现,不会在负载下杀死你的数据库,那么你应该使用一个针对目的而定制的解决scheme。 stream行的例子包括Solr或狮身人面像,还有很多其他的。 通过这个实现,既然你干了,你可以在一个地方用一个单独的索引器replace实现,你就可以准备好了。

非常像上面的答案,但是如果你使用的是ActiveRecord … 2.1或者更高版本,你可以使用一个命名的作用域,它允许你在通过关联检索的logging上使用这个“finder”

 class User named_scope :with_name_like, lambda {|str| :conditions => ['lower(name) like ?', %(%#{str.downcase}%)] } end 

用于:

 User.with_name_like("Samson") 

(使用“Samson”这样的名字返回数据库中的所有用户。

要么:

 some_association.users.with_name_like("Samson") 

用户只能使用“Samson”这个名字。

我不想每次想查看一个特定的列是否以一个前缀开始时写一个范围。

 # initializers/active_record_initializers.rb class ActiveRecord::Base # do not accept a column_name from the outside without sanitizing it # as this can be prone to sql injection def self.starts_with(column_name, prefix) where("lower(#{column_name}) like ?", "#{prefix.downcase}%") end end 

像这样调用它:

 User.starts_with('name', 'ab').limit(1) 

现在是2012年,我想我会把这个更新纳入纳尔斯克的答案。

named_scope变得简单的scope ,所以这个例子变成了

 class User scope :name_starts_with, lambda {|str| :conditions => ['lower(name) like ?', "#{str.downcase}%"] } end 

注意我从narsk的解决scheme中删除了第一个% ,因为OP要求的是“starts_with”而不是“contains”匹配。

现在你可以做类似的事情了

 User.name_starts_with("b").each do {|bs| puts bs.inspect} bob = User.name_starts_with("bob").first … etc 

请注意,范围总是返回集合 ,而不是个别的结果。 当我刚刚开始使用AR时,这让我感到不快,我仍然设法忘记了这一切。

戴夫萨格,我想你的代码的第一部分应该是

 class User scope :name_starts_with, (lambda do |str| {:conditions => ['lower(name) like ?', "#{str.downcase}%"]} end ) end 

对于同样的事情,非常简洁的语法可能是:

 Model.where(field: ('prefix'...'prefiy')) 

这使得:

 WHERE ( field >= 'prefix' AND field < 'prefiy') 

这是作为“prefiy”的工作,是第一个string不符合“前缀”前缀。

我不会正常使用它(我会去squeel或ransack代替),但它可以节省你的一天,如果由于某种原因,你必须坚持散列语法的查询…