Meu modelo de produto contém alguns itens
Product.first
=> #<Product id: 10, name: "Blue jeans" >
Agora estou importando alguns parâmetros do produto de outro conjunto de dados, mas há inconsistências na ortografia dos nomes. Por exemplo, no outro conjunto de dados, Blue jeans
poderia ser escrito Blue Jeans
.
Eu queria Product.find_or_create_by_name("Blue Jeans")
, mas isso criará um novo produto, quase idêntico ao primeiro. Quais são minhas opções se eu quiser encontrar e comparar o nome em minúsculas.
Os problemas de desempenho não são realmente importantes aqui: existem apenas 100-200 produtos e eu quero executá-lo como uma migração que importa os dados.
Alguma ideia?
ruby-on-rails
activerecord
case-insensitive
Jesper Rønn-Jensen
fonte
fonte
"$##"
e'$##'
. O primeiro é interpolado (aspas duplas). O segundo não é. A entrada do usuário nunca é interpolada.find(:first)
está obsoleto e a opção agora é usar#first
. Assim,Product.first(conditions: [ "lower(name) = ?", name.downcase ])
model = Product.where('lower(name) = ?', name.downcase).first_or_create
after_create
retorno de chamada noProduct
modelo e dentro do retorno de chamada, tenhamoswhere
cláusula, por exemploproducts = Product.where(country: 'us')
. Nesse caso, aswhere
cláusulas são encadeadas à medida que os retornos de chamada são executados no contexto do escopo. Apenas para sua informação.Esta é uma configuração completa no Rails, para minha própria referência. Fico feliz se isso também ajudar.
A pergunta:
o validador:
o índice (resposta do índice exclusivo que não diferencia maiúsculas de minúsculas no Rails / ActiveRecord? ):
Eu gostaria que houvesse uma maneira mais bonita de fazer a primeira e a última, mas, novamente, o Rails e o ActiveRecord são de código aberto, não devemos reclamar - podemos implementá-lo nós mesmos e enviar solicitação de recebimento.
fonte
find(:first, ...)
agora está obsoleto, acho que esta é a resposta mais adequada.Product.where("lower(name) = ?", name).first
Se você estiver usando Postegres e Rails 4+, terá a opção de usar o tipo de coluna CITEXT, que permitirá consultas sem distinção entre maiúsculas e minúsculas sem precisar escrever a lógica da consulta.
A migração:
E para testá-lo, você deve esperar o seguinte:
fonte
Você pode querer usar o seguinte:
Observe que, por padrão, a configuração é: case_sensitive => false, para que você nem precise escrever essa opção se não tiver alterado outras maneiras.
Encontre mais em: http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#method-i-validates_uniqueness_of
fonte
No postgres:
fonte
Vários comentários se referem à Arel, sem fornecer um exemplo.
Aqui está um exemplo da Arel de uma pesquisa que não diferencia maiúsculas de minúsculas:
A vantagem desse tipo de solução é que ele é independente do banco de dados - ele usará os comandos SQL corretos para o seu adaptador atual (
matches
oILIKE
Postgres eLIKE
todo o resto).fonte
Citando a partir da documentação do SQLite :
... o que eu não sabia.Mas funciona:
Então você poderia fazer algo assim:
Não
#find_or_create
, eu sei, e pode não ser muito compatível com vários bancos de dados, mas vale a pena olhar?fonte
Outra abordagem mencionada por ninguém é adicionar localizadores que não diferenciam maiúsculas de minúsculas no ActiveRecord :: Base. Detalhes podem ser encontrados aqui . A vantagem dessa abordagem é que você não precisa modificar todos os modelos e não precisa adicionar a
lower()
cláusula a todas as consultas sem distinção entre maiúsculas e minúsculas; basta usar um método localizador diferente.fonte
Letras maiúsculas e minúsculas diferem apenas em um único bit. A maneira mais eficiente de procurá-los é ignorar esse bit, não converter inferior ou superior, etc. Veja palavras-chave
COLLATION
para MSSQL, vejaNLS_SORT=BINARY_CI
se está usando Oracle etc.fonte
Find_or_create agora está obsoleto, você deve usar uma relação de AR e first_or_create, da seguinte forma:
Isso retornará o primeiro objeto correspondido ou criará um para você, se não houver nenhum.
fonte
A pesquisa que não diferencia maiúsculas de minúsculas é integrada ao Rails. É responsável por diferenças nas implementações de banco de dados. Use a biblioteca interna do Arel ou uma jóia como o Squeel .
fonte
Há muitas ótimas respostas aqui, principalmente as da @ oma. Mas outra coisa que você pode tentar é usar a serialização de coluna personalizada. Se você não se importa de tudo ser armazenado em minúsculas no seu banco de dados, você pode criar:
Então no seu modelo:
O benefício dessa abordagem é que você ainda pode usar todos os localizadores regulares (incluindo
find_or_create_by
) sem usar escopos, funções ou terlower(name) = ?
em suas consultas.A desvantagem é que você perde as informações da caixa no banco de dados.
fonte
Semelhante ao Andrews, que é o número 1:
Algo que funcionou para mim é:
Isso elimina a necessidade de fazer uma
#where
e#first
na mesma consulta. Espero que isto ajude!fonte
Você também pode usar escopos como este abaixo e colocá-los em uma preocupação e incluir nos modelos que podem ser necessários:
scope :ci_find, lambda { |column, value| where("lower(#{column}) = ?", value.downcase).first }
Então use assim:
Model.ci_find('column', 'value')
fonte
Supondo que você use o mysql, você pode usar campos que não diferenciam maiúsculas de minúsculas: http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html
fonte
fonte
TypeError: Cannot visit Regexp
Algumas pessoas mostram usando LIKE ou ILIKE, mas elas permitem pesquisas de expressões regulares. Além disso, você não precisa fazer downcase no Ruby. Você pode deixar o banco de dados fazer isso por você. Eu acho que pode ser mais rápido. Também
first_or_create
pode ser usado depoiswhere
.fonte
Uma alternativa pode ser
fonte
Até agora, eu fiz uma solução usando Ruby. Coloque isso dentro do modelo do produto:
Isso me dará o primeiro produto em que os nomes correspondem. Ou nada.
fonte