Ruby-on-rails ActiveRecord 查找开始于
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/251345/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ActiveRecord find starts with
提问by robintw
Really simple question - how do I do a search to find all records where the name starts with a certain string in ActiveRecord. I've seen all sorts of bits all over the internet where verbatim LIKE SQL clauses are used - but from what I've heard that isn't the 'correct' way of doing it.
非常简单的问题 - 我如何搜索以查找名称以 ActiveRecord 中某个字符串开头的所有记录。我已经在互联网上看到了使用逐字 LIKE SQL 子句的各种位 - 但据我所知,这不是“正确”的做法。
Is there a 'proper' Rails way?
有“合适的”Rails 方式吗?
采纳答案by Owen
I would highly recommend the Searchlogicplugin.
我强烈推荐Searchlogic插件。
Then it's as easy as:
然后就这么简单:
@search = Model.new_search(params[:search])
@search.condition.field_starts_with = "prefix"
@models = @search.all
Searchlogic is smart enough, like ActiveRecord, to pick up on the field name in the starts_withcondition. It will also handle all pagination.
Searchlogic 很聪明,就像 ActiveRecord 一样,可以在starts_with条件中选取字段名称。它还将处理所有分页。
This method will help prevent SQL injection and also will be database agnostic. Searchlogic ends up handling the search differently depending on the database adapter you're using. You also don't have to write any SQL!
此方法将有助于防止 SQL 注入,并且与数据库无关。Searchlogic 最终会根据您使用的数据库适配器以不同方式处理搜索。您也不必编写任何 SQL!
Searchlogic has great documentation and is easy to use (I'm new to Ruby and Rails myself). When I got stuck, the author of the plugin even answered a direct email within a few hours helping me fix my problem. I can't recommend Searchlogic enough...as you can tell.
Searchlogic 有很好的文档并且易于使用(我自己是 Ruby 和 Rails 的新手)。当我卡住时,插件的作者甚至在几个小时内直接回复了一封电子邮件,帮助我解决了问题。我不能推荐足够多的 Searchlogic ......正如你所知道的。
回答by Gareth
If you're looking to do the search in the database then you'll need to use SQL.
如果您想在数据库中进行搜索,那么您需要使用 SQL。
And, of course, you'll need to do the search in the database otherwise you need to load allthe objects into Ruby (which isn't a good thing).
而且,当然,您需要在数据库中进行搜索,否则您需要将所有对象加载到 Ruby 中(这不是一件好事)。
So, you will need something like
所以,你需要像
MyModel.find(:all, :conditions => ["field LIKE ?", "#{prefix}%"])
where prefixis a variable with the string you're looking for.
whereprefix是带有您要查找的字符串的变量。
In Rails 3.0+ this becomes:
在 Rails 3.0+ 中,这变成了:
MyModel.where("field LIKE :prefix", prefix: "#{prefix}%")
回答by Larry
Disclaimer: I am new to Ruby and Rails, and I am still trying to learn the Ruby Way to do things, but I have been coding for more than half of my life, and professionally for a decade. DRY is a concept with which I am very familiar. Here is how I implemented it. It is very similar to narsk's answer, which I think is also good.
免责声明:我是 Ruby 和 Rails 的新手,我仍在努力学习 Ruby 的做事方式,但我已经用了半生以上的时间进行编码,并且已经从事了十年的专业工作。DRY 是一个我非常熟悉的概念。这是我如何实施它。它与narsk的回答非常相似,我认为这也很好。
# 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
And then in your model:
然后在你的模型中:
class User < ActiveRecord::Base
extend NameSearchable
...
end
And then when you want to use it:
然后当你想使用它时:
User.search_by_prefix('John') #or
User.search_by_prefix("#{name_str}")
One thing to call out:
需要提醒的一件事:
Traditional relational databases aren't extremely good at satisfying these kinds of queries. If you are looking for a highly responsive implementation that will not kill your databases under load, you should probably use a solution that is tailored to the purpose instead. Popular examples include Solr or Sphinx, and there are many others as well. With this implementation, since you DRY, you could substitute the implementation with a separate indexer in just one place and you would be ready to rock.
传统的关系数据库不太擅长满足这些类型的查询。如果您正在寻找一种不会在负载下杀死您的数据库的高度响应的实现,您可能应该使用针对该目的量身定制的解决方案。流行的示例包括 Solr 或 Sphinx,还有许多其他示例。有了这个实现,因为你 DRY,你可以在一个地方用一个单独的索引器替换这个实现,你就可以开始摇滚了。
回答by Abdo
I don't want to write a scope every time I want to see if a specific column starts_with a prefix.
我不想每次想查看特定列是否以前缀开头时都编写范围。
# 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
Call it like this:
像这样调用它:
User.starts_with('name', 'ab').limit(1)
回答by narsk
Very much like the above answer, but if you're using ActiveRecord...2.1 or greater, you could use a named scope which would allow you to use this "finder" on records retrieved thru associations:
非常像上面的答案,但如果您使用的是 ActiveRecord...2.1 或更高版本,则可以使用命名范围,它允许您在通过关联检索的记录上使用此“查找器”:
class User
named_scope :with_name_like, lambda {|str|
:conditions => ['lower(name) like ?', %(%#{str.downcase}%)]
}
end
Used like:
像这样使用:
User.with_name_like("Samson")
(returns all users in your database with a name like "Samson".
(返回数据库中名称为“Samson”的所有用户。
Or:
或者:
some_association.users.with_name_like("Samson")
Users off that association only with a name like "Samson".
仅使用“Samson”之类的名称关闭该关联的用户。
回答by Dave Sag
Now it's 2012 I thought I'd throw in this update to narsk's answer.
现在是 2012 年,我想我会将此更新用于 narsk 的回答。
named_scopebecame simply scopea while ago so the example becomes
named_scopescope不久前就变得简单了,所以这个例子变成了
class User
scope :name_starts_with, lambda {|str|
:conditions => ['lower(name) like ?', "#{str.downcase}%"]
}
end
Note I removed the first %from narsk's solution as the OP is asking for a 'starts_with' not a 'contains' match.
注意我%从 narsk 的解决方案中删除了第一个,因为 OP 要求的是“starts_with”而不是“contains”匹配。
Now you can do things like
现在你可以做这样的事情
User.name_starts_with("b").each do {|bs| puts bs.inspect}
bob = User.name_starts_with("bob").first
… etc
Note that scopes always return collections, never individual results. That threw me when I was first starting out with AR and I still manage to forget that every now and again.
请注意,范围始终返回集合,而不是单个结果。当我第一次开始使用 AR 时,这让我很震惊,但我仍然时不时地忘记这一点。
回答by Oriettaxx
Dave Sag, I guess the first part of your code should be
Dave Sag,我猜你的代码的第一部分应该是
class User
scope :name_starts_with, (lambda do |str|
{:conditions => ['lower(name) like ?', "#{str.downcase}%"]}
end )
end
回答by bert bruynooghe
Very terse syntax for the same thing might be:
同一件事的非常简洁的语法可能是:
Model.where(field: ('prefix'...'prefiy'))
This renders:
这呈现:
WHERE ( field >= 'prefix' AND field < 'prefiy')
This does the job as 'prefiy'is the first string alphabetically not matching the 'prefix'prefix.
这是因为'prefiy'是按字母顺序排列的第一个与'prefix'前缀不匹配的字符串。
I would not use it normally (I would go for squeel or ransack instead), but it can save your day if for some reason you have to stick to hash syntax for the queries...
我不会正常使用它(我会去使用 squeel 或 ransack),但是如果由于某种原因你必须坚持查询的哈希语法,它可以节省你的一天......

