Поиск без учета регистра в модели Rails

Моя модель продукта содержит некоторые объекты

 Product.first
 => #<Product id: 10, name: "Blue jeans" >

Я теперь импортирую некоторые параметры продукта из другого набора данных, но существуют несоответствия в написании имен. Например, в другом наборе данных, Blue jeans мог быть записан Blue Jeans.

Я хотел Product.find_or_create_by_name("Blue Jeans"), но это создаст новый продукт, почти идентичный первому. Каковы мои опции, если я хочу найти и сравнить печатавшее строчными литерами имя.

Проблемы производительности не действительно важны здесь: существует только 100-200 продуктов, и я хочу выполнить это как миграцию, которая импортирует данные.

Какие-либо идеи?

206
задан Jesper Rønn-Jensen 7 February 2010 в 22:55
поделиться

7 ответов

Вам, вероятно, придется быть более подробным здесь

name = "Blue Jeans"
model = Product.where('lower(name) = ?', name.downcase).first 
model ||= Product.create(:name => name)
354
ответ дан 23 November 2019 в 04:46
поделиться

Цитирую по документации SQLite:

Любой другой символ соответствует самому себе или его эквивалент в нижнем/верхнем регистре (т.е. нечувствительное к регистру соответствие)

... чего я не знал. Но это работает:

sqlite> create table products (name string);
sqlite> insert into products values ("Blue jeans");
sqlite> select * from products where name = 'Blue Jeans';
sqlite> select * from products where name like 'Blue Jeans';
Blue jeans

Так что вы могли бы сделать что-то вроде этого:

name = 'Blue jeans'
if prod = Product.find(:conditions => ['name LIKE ?', name])
    # update product or whatever
else
    prod = Product.create(:name => name)
end

Не #find_or_create, я знаю, и это может быть не очень дружелюбно к базе данных, но стоит посмотреть?

.
9
ответ дан 23 November 2019 в 04:46
поделиться

Вы можете использовать следующее:

validates_uniqueness_of :name, :case_sensitive => false

Обратите внимание, что по умолчанию настройка: case_sensitive => false, поэтому вам даже не нужно написать этот вариант, если вы не изменили другие способы.

Дополнительные сведения см. По адресу: http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#method-i-validates_uniqueness_of

21
ответ дан 23 November 2019 в 04:46
поделиться

До сих пор я делал решение, используя Ruby. Поместите это в модель продукта:

  #return first of matching products (id only to minimize memory consumption)
  def self.custom_find_by_name(product_name)
    @@product_names ||= Product.all(:select=>'id, name')
    @@product_names.select{|p| p.name.downcase == product_name.downcase}.first
  end

  #remember a way to flush finder cache in case you run this from console
  def self.flush_custom_finder_cache!
    @@product_names = nil
  end

Это даст мне первый продукт, названия которого совпадают. Или ноль.

>> Product.create(:name => "Blue jeans")
=> #<Product id: 303, name: "Blue jeans">

>> Product.custom_find_by_name("Blue Jeans")
=> nil

>> Product.flush_custom_finder_cache!
=> nil

>> Product.custom_find_by_name("Blue Jeans")
=> #<Product id: 303, name: "Blue jeans">
>>
>> #SUCCESS! I found you :)
-9
ответ дан 23 November 2019 в 04:46
поделиться

Предполагая, что вы используете mysql, вы можете использовать поля без учета регистра: http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html

0
ответ дан 23 November 2019 в 04:46
поделиться

Другой подход, о котором никто не упоминал, - это добавление средств поиска без учета регистра в ActiveRecord :: Base. Подробности можно найти здесь . Преимущество этого подхода заключается в том, что вам не нужно изменять каждую модель, и вам не нужно добавлять предложение lower () во все ваши нечувствительные к регистру запросы, вы просто используете другой метод поиска вместо.

5
ответ дан 23 November 2019 в 04:46
поделиться

Буквы верхнего и нижнего регистра отличаются только одним битом. Самый эффективный способ их поиска - игнорировать этот бит, не преобразовывать нижнее или верхнее и т. Д. См. Ключевые слова COLLATION для MSSQL, см. NLS_SORT = BINARY_CI при использовании Oracle и т. Д.

6
ответ дан 23 November 2019 в 04:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: