7

我希望能够做到Artist.case_insensitive_find_or_create_by_name(artist_name)[1](并让它在 sqlite 和 postgreSQL 上都可以工作)

实现这一目标的最佳方法是什么?现在我只是直接向Artist类添加一个方法(有点难看,特别是如果我想在另一个类中使用这个功能,但无论如何):

  def self.case_insensitive_find_or_create_by_name(name)
    first(:conditions => ['UPPER(name) = UPPER(?)', name]) || create(:name => name)
  end

[1]:嗯,理想情况下是这样Artist.find_or_create_by_name(artist_name, :case_sensitive => false),但这似乎更难实现

4

4 回答 4

18

Rails 4 为您提供了一种方法来完成同样的事情:

Artist.where('lower(name) = ?', name.downcase).first_or_create(:name=>name)

于 2015-01-07T09:27:08.753 回答
7

此答案适用于问题评论中提出的其他问题。

find_or_create_by_name如果您覆盖该方法,您将无法调用默认值。但是您可以实现自己的,如下所示:

def self.find_or_create_by_name(*args)
  options = args.extract_options!
  options[:name] = args[0] if args[0].is_a?(String)
  case_sensitive = options.delete(:case_sensitive)
  conditions = case_sensitive ? ['name = ?', options[:name]] : 
                                ['UPPER(name) = ?', options[:name].upcase] 
  first(:conditions => conditions) || create(options)
end

现在您可以按如下方式调用被覆盖的方法:

User.find_or_create_by_name("jack")
User.find_or_create_by_name("jack", :case_sensitive => true)
User.find_or_create_by_name("jack", :city=> "XXX", :zip => "1234")
User.find_or_create_by_name("jack", :zip => "1234", :case_sensitive => true)
于 2010-03-13T17:37:20.777 回答
5

您必须基于数据库创建索引。

PostgreSQL

artist_name在列上创建小写索引。

CREATE INDEX lower_artists_name ON artists(lower(artist_name))

mysql

搜索不区分大小写

sqllite

artist_name使用 collat​​e 参数在列上创建索引

CREATE INDEX lower_artists_name ON artists( artist_name collate nocase)

现在您可以以独立于数据库的方式使用 find_or_create :

find_or_create_by_artist_name(lower(artist_name))

参考

PostgreSQL:不区分大小写的搜索

sqlLite:不区分大小写的搜索

于 2010-03-12T21:22:21.973 回答
1

这里谈到了这一点。没有人能想出比你更好的解决方案 :)

于 2010-03-12T21:02:24.543 回答