Без учета регистра find_or_create_by_wh независимо - PullRequest
6 голосов
/ 12 марта 2010

Я хочу иметь возможность сделать 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 ]

16 голосов
/ 07 января 2015

Rails 4 дает вам возможность сделать то же самое:

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

7 голосов
/ 13 марта 2010

Этот ответ предназначен для дополнительных вопросов, заданных в комментариях к вопросу.

Вы не сможете вызвать значение по умолчанию 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)
5 голосов
/ 13 марта 2010

Вы должны создать индекс на основе базы данных.

PostGreSQL

Создание строчного индекса в столбце artist_name.

CREATE INDEX lower_artists_name ON artists(lower(artist_name))

mySQL

Поиск нечувствителен к регистру

sqlLite

Создать индекс для столбца 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: поиск без учета регистра

1 голос
/ 13 марта 2010

Об этом говорили здесь . Никто не смог придумать решение лучше, чем ваше:)

...