Моя модель продукта содержит некоторые элементы
Product.first
=> #<Product id: 10, name: "Blue jeans" >
Сейчас я импортирую некоторые параметры продукта из другого набора данных, но есть несоответствия в написании имен. Например, в другом наборе данных Blue jeans
может быть написано Blue Jeans
.
Я хотел Product.find_or_create_by_name("Blue Jeans")
, но это создаст новый продукт, практически идентичный первому. Каковы мои варианты, если я хочу найти и сравнить имя в нижнем регистре.
Проблемы с производительностью на самом деле здесь не важны: есть только 100-200 продуктов, и я хочу запустить их как миграцию, которая импортирует данные.
Любые идеи?
ruby-on-rails
activerecord
case-insensitive
Джеспер Ренн-Йенсен
источник
источник
"$##"
и'$##'
. Первый интерполируется (двойные кавычки). Второго нет. Пользовательский ввод никогда не интерполируется.find(:first)
это устарело, и вариант теперь использовать#first
. Таким образом,Product.first(conditions: [ "lower(name) = ?", name.downcase ])
model = Product.where('lower(name) = ?', name.downcase).first_or_create
after_create
обратный вызов вProduct
модели и внутри обратного вызова, у нас естьwhere
предложение, напримерproducts = Product.where(country: 'us')
. В этом случаеwhere
предложения объединяются в цепочку при выполнении обратных вызовов в контексте области. Просто к вашему сведению.Это полная настройка в Rails, для моей справки. Я счастлив, если тебе это тоже поможет.
запрос:
валидатор:
индекс (ответ из уникального регистра без учета регистра в Rails / ActiveRecord? ):
Хотелось бы, чтобы был более красивый способ сделать первый и последний, но опять же, Rails и ActiveRecord с открытым исходным кодом, мы не должны жаловаться - мы можем реализовать это сами и отправить запрос на извлечение.
источник
find(:first, ...)
это устарело, я думаю, что это самый правильный ответ.Product.where("lower(name) = ?", name).first
Если вы используете Postegres и Rails 4+, то у вас есть возможность использовать тип столбца CITEXT, что позволит выполнять запросы без учета регистра без необходимости выписывать логику запроса.
Миграция:
И чтобы проверить это, вы должны ожидать следующее:
источник
Возможно, вы захотите использовать следующее:
Обратите внимание, что по умолчанию установлено значение case_sensitive => false, поэтому вам даже не нужно писать эту опцию, если вы не изменили другие способы.
Узнайте больше по адресу: http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#method-i-validates_uniqueness_of
источник
В postgres:
источник
Несколько комментариев относятся к Арелу, без предоставления примера.
Вот пример Arel для поиска без учета регистра:
Преимущество этого типа решения заключается в том, что оно не зависит от базы данных - оно будет использовать правильные команды SQL для вашего текущего адаптера (
matches
будет использоватьсяILIKE
для Postgres иLIKE
для всего остального).источник
Цитирование из документации SQLite :
... который я не знал. Но это работает:
Таким образом, вы можете сделать что-то вроде этого:
Не
#find_or_create
, я знаю, и это может быть не очень дружелюбно к базе данных, но стоит посмотреть?источник
Другой подход, о котором никто не упомянул, заключается в добавлении нечувствительных к регистру искателей в ActiveRecord :: Base. Подробности можно найти здесь . Преимущество этого подхода состоит в том, что вам не нужно изменять каждую модель, и вам не нужно добавлять
lower()
предложение ко всем вашим запросам без учета регистра, вместо этого вы просто используете другой метод поиска.источник
Прописные и строчные буквы отличаются только на один бит. Наиболее эффективный способ их поиска - игнорировать этот бит, не преобразовывать нижний или верхний и т. Д. См. Ключевые слова
COLLATION
для MSSQL, посмотритеNLS_SORT=BINARY_CI
, используете ли Oracle, и т. Д.источник
Find_or_create теперь устарела, вместо этого вы должны использовать AR Relation плюс first_or_create, вот так:
Это вернет первый соответствующий объект или создаст его для вас, если его не существует.
источник
Поиск без учета регистра встроен в Rails. Это объясняет различия в реализации баз данных. Используйте либо встроенную библиотеку Arel, либо драгоценный камень, такой как Squeel .
источник
Здесь много хороших ответов, особенно @ oma. Но есть еще одна вещь, которую вы можете попробовать - использовать пользовательскую сериализацию столбцов. Если вы не возражаете против хранения всего нижнего регистра в вашей базе данных, вы можете создать:
Тогда в вашей модели:
Преимущество этого подхода состоит в том, что вы все еще можете использовать все обычные средства поиска (включая
find_or_create_by
) без использования пользовательских областей действия, функций или наличияlower(name) = ?
в ваших запросах.Недостатком является то, что вы теряете информацию об корпусе в базе данных.
источник
Подобно Эндрюсу, который является # 1:
Что-то, что сработало для меня:
Это избавляет от необходимости делать один
#where
и#first
тот же запрос. Надеюсь это поможет!источник
Вы также можете использовать такие области, как это ниже, и поставить их под вопрос и включить в модели, которые могут вам понадобиться:
scope :ci_find, lambda { |column, value| where("lower(#{column}) = ?", value.downcase).first }
Затем используйте как это:
Model.ci_find('column', 'value')
источник
Предполагая, что вы используете mysql, вы можете использовать поля, не чувствительные к регистру: http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html
источник
источник
TypeError: Cannot visit Regexp
Некоторые люди показывают, используя LIKE или ILIKE, но те позволяют поиск по регулярному выражению. Также вам не нужно заглядывать в Ruby. Вы можете позволить базе данных сделать это за вас. Я думаю, что это может быть быстрее. Также
first_or_create
можно использовать послеwhere
.источник
Альтернативой может быть
источник
Пока что я сделал решение, используя Ruby. Поместите это внутри модели продукта:
Это даст мне первый продукт, где имена совпадают. Или ноль.
источник