不区分大小写的find_or_create_by_whatever

我希望能够做Artist.case_insensitive_find_or_create_by_name(artist_name) [1](并使它适用于sqlite和postgreSQL)

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

  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) ,但这似乎更难实现

这个答案是针对问题评论中提出的其他问题。

如果覆盖该方法,则无法调用默认的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) 

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

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

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

PostgreSQL的

artist_name列上创建小写索引。

 CREATE INDEX lower_artists_name ON artists(lower(artist_name)) 

MySQL的

搜索不区分大小写

sqlLite

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

 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:不区分大小写的搜索

在这里谈到这个。 没有人能够提出比你更好的解决方案:)