Case-insensitive find_or_create_by_whatever

后端 未结 4 1055
天命终不由人
天命终不由人 2021-01-12 15:58

I want to be able to do Artist.case_insensitive_find_or_create_by_name(artist_name)[1] (and have it work on both sqlite and postgreSQL)

What\'s the best

相关标签:
4条回答
  • 2021-01-12 16:17

    Talked about this one here. No one was able to come up with a solution better than yours :)

    0 讨论(0)
  • 2021-01-12 16:20

    You have to create an index based on the database.

    postgreSQL

    Create a lower case index on artist_name column.

    CREATE INDEX lower_artists_name ON artists(lower(artist_name))
    

    mySQL

    Searches are case insensitive

    sqlLite

    Create a index on artist_name column with collate parameter

    CREATE INDEX lower_artists_name ON artists( artist_name collate nocase)
    

    Now you can use find_or_create in a DB independent manner:

    find_or_create_by_artist_name(lower(artist_name))
    

    Reference

    PostgreSQL: Case insensitive search

    sqlLite: Case insensitive search

    0 讨论(0)
  • 2021-01-12 16:25

    This answer is for the additional questions asked in the question comments.

    You wont be able to call the default find_or_create_by_name if you override that method. But you can implement your own as shown below:

    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
    

    Now you can call the overridden method as follows:

    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)
    
    0 讨论(0)
  • 2021-01-12 16:32

    Rails 4 gives you a way to accomplish the same thing:

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

    0 讨论(0)
提交回复
热议问题