Meu modelo de produto contém alguns itens
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 jeanspoderia 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.
Você provavelmente terá que ser mais detalhado aqui
— alex.zherdev
O comentário do @ botbot não se aplica a strings da entrada do usuário. "# $$" é um atalho pouco conhecido para escapar de variáveis ​​globais com interpolação de string Ruby. É equivalente a "# {$$}". Mas a interpolação de strings não acontece com as strings de entrada do usuário. Experimente estes no Irb para ver a diferença: "$##"e '$##'. O primeiro é interpolado (aspas duplas). O segundo não é. A entrada do usuário nunca é interpolada.
Apenas observe que find(:first)está obsoleto e a opção agora é usar #first. Assim,Product.first(conditions: [ "lower(name) = ?", name.downcase ])
Você não precisa fazer todo esse trabalho. Use a biblioteca interna da Arel ou Squeel
No Rails 4 agora você pode fazermodel = Product.where('lower(name) = ?', name.downcase).first_or_create
— Derek Lucas
@DerekLucas, embora seja possível fazê-lo no Rails 4, esse método pode causar um comportamento inesperado. Suponha que tenhamos after_createretorno de chamada no Productmodelo e dentro do retorno de chamada, tenhamos wherecláusula, por exemplo products = Product.where(country: 'us'). Nesse caso, as wherecláusulas são encadeadas à medida que os retornos de chamada são executados no contexto do escopo. Apenas para sua informação.
— Elquimista 4/16
Esta é uma configuração completa no Rails, para minha própria referência. Fico feliz se isso também ajudar.
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.
Obrigado pelo crédito na criação do índice que não diferencia maiúsculas de minúsculas no PostgreSQL. Devolva-lhe o crédito por mostrar como usá-lo no Rails! Uma observação adicional: se você usar um localizador padrão, por exemplo, find_by_name, ele ainda fará uma correspondência exata. Você precisa escrever localizadores personalizados, semelhantes à sua linha de "consulta" acima, se quiser que sua pesquisa não diferencie maiúsculas de minúsculas.
— Marque 'Berry
Considerando que find(:first, ...)agora está obsoleto, acho que esta é a resposta mais adequada.
é necessário name.downcase? Parece que funciona comProduct.where("lower(name) = ?", name).first
@ Jordan você já tentou isso com nomes com letras maiúsculas?
@Jordan, talvez não muito importante, mas devemos nos esforçar para precisão no SO como estamos ajudando os outros :)
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.
E para testá-lo, você deve esperar o seguinte:
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
Na minha experiência, em contraste com a documentação, case_sensitive é verdadeiro por padrão. Eu já vi esse comportamento no postgresql e outros relataram o mesmo no mysql.
então estou tentando isso com o postgres e não funciona. find_by_x é sensível a maiúsculas, independentemente ...
— Louis Sayers
Essa validação é apenas ao criar o modelo. Portanto, se você tiver 'HAML' em seu banco de dados e tentar adicionar 'haml', ele não passará nas validações.
— Dudo 10/10
Trilhos no Heroku, então usando o Postgres… ILIKE é brilhante. Obrigado!
— FeifanZ 06/07/2013
Definitivamente usando o ILIKE no PostgreSQL.
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 ( matcheso ILIKEPostgres e LIKEtodo o resto).
Citando a partir da documentação do SQLite :
Qualquer outro caractere corresponde a si mesmo ou a seu equivalente em maiúsculas / minúsculas (ou seja, correspondência que não diferencia maiúsculas de minúsculas)
... o que eu não sabia.Mas funciona:
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?
like diferencia maiúsculas de minúsculas no mysql, mas não no postgresql. Não tenho certeza sobre Oracle ou DB2. O ponto é que você não pode contar com isso e se você o usar e seu chefe alterar seu banco de dados subjacente, você começará a ter registros "ausentes" sem uma razão óbvia. A sugestão mais baixa (nome) de neutrino é provavelmente a melhor maneira de resolver isso.
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.
— Alex Korban
quando a página que você vincula morre, o mesmo acontece com a sua resposta.
Como profetizou o @Anthony, isso aconteceu. Link morto.
— XP84 24/0718
@ XP84 Não sei mais o quanto isso é relevante, mas consertei o link.
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 COLLATIONpara MSSQL, veja NLS_SORT=BINARY_CIse está usando Oracle etc.
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.
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 .
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 ter lower(name) = ?em suas consultas.
A desvantagem é que você perde as informações da caixa no banco de dados.
— Nate Murray
Semelhante ao Andrews, que é o número 1:
Algo que funcionou para mim é:
Isso elimina a necessidade de fazer uma #wheree #firstna mesma consulta. Espero que isto ajude!
— Jonathan Fairbanks
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:
Então use assim: Model.ci_find('column', 'value')
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
@shilovk thanks. Era exatamente isso que eu estava procurando. E parecia melhor do que a resposta aceita stackoverflow.com/a/2220595/1380867
Eu gosto dessa solução, mas como você passou pelo erro "Não é possível visitar o Regexp"? Eu também estou vendo isso.
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_createpode ser usado depois where.
— 6ft Dan
Uma alternativa pode ser
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.
Isso é extremamente ineficiente para um conjunto de dados maior, pois ele precisa carregar tudo na memória. Embora não seja um problema para você, com apenas algumas centenas de entradas, isso não é uma boa prática.