Mi modelo de producto contiene algunos artículos.
Product.first
=> #<Product id: 10, name: "Blue jeans" >
Ahora estoy importando algunos parámetros del producto desde otro conjunto de datos, pero hay inconsistencias en la ortografía de los nombres. Por ejemplo, en el otro conjunto de datos, Blue jeans
podría escribirse Blue Jeans
.
Quería hacerlo Product.find_or_create_by_name("Blue Jeans")
, pero esto creará un nuevo producto, casi idéntico al primero. ¿Cuáles son mis opciones si quiero encontrar y comparar el nombre en minúsculas?
Los problemas de rendimiento no son realmente importantes aquí: solo hay entre 100 y 200 productos, y quiero ejecutar esto como una migración que importa los datos.
¿Algunas ideas?
ruby-on-rails
activerecord
case-insensitive
Jesper Rønn-Jensen
fuente
fuente
"$##"
y'$##'
. El primero es interpolado (comillas dobles). El segundo no es. La entrada del usuario nunca se interpola.find(:first)
está en desuso, y la opción ahora es usar#first
. Así,Product.first(conditions: [ "lower(name) = ?", name.downcase ])
model = Product.where('lower(name) = ?', name.downcase).first_or_create
after_create
devolución de llamada en elProduct
modelo y dentro de la devolución de llamada, tenemos unawhere
cláusula, por ejemploproducts = Product.where(country: 'us')
. En este caso, laswhere
cláusulas se encadenan a medida que las devoluciones de llamada se ejecutan dentro del contexto del ámbito. Solo para tu información.Esta es una configuración completa en Rails, para mi propia referencia. Estoy feliz si te ayuda también.
la consulta:
el validador:
el índice (respuesta de índice único que no distingue entre mayúsculas y minúsculas en Rails / ActiveRecord? ):
Desearía que hubiera una forma más hermosa de hacer lo primero y lo último, pero, una vez más, Rails y ActiveRecord son de código abierto, no deberíamos quejarnos: podemos implementarlo nosotros mismos y enviar una solicitud de extracción.
fuente
find(:first, ...)
ahora está en desuso, creo que esta es la respuesta más adecuada.Product.where("lower(name) = ?", name).first
Si está utilizando Postegres y Rails 4+, tiene la opción de usar el tipo de columna CITEXT, que permitirá consultas que no distinguen entre mayúsculas y minúsculas sin tener que escribir la lógica de la consulta.
La migración:
Y para probarlo, debe esperar lo siguiente:
fuente
Es posible que desee utilizar lo siguiente:
Tenga en cuenta que, de forma predeterminada, la configuración es: case_sensitive => false, por lo que ni siquiera necesita escribir esta opción si no ha cambiado otras formas.
Encuentre más en: http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#method-i-validates_uniqueness_of
fuente
En postgres:
fuente
Varios comentarios se refieren a Arel, sin proporcionar un ejemplo.
Aquí hay un ejemplo de Arel de una búsqueda que no distingue entre mayúsculas y minúsculas:
La ventaja de este tipo de solución es que es independiente de la base de datos: usará los comandos SQL correctos para su adaptador actual (
matches
lo usaráILIKE
para Postgres yLIKE
para todo lo demás).fuente
Citando de la documentación de SQLite :
... que no sabía, pero funciona:
Entonces podrías hacer algo como esto:
No
#find_or_create
, lo sé, y puede que no sea muy compatible con todas las bases de datos, pero ¿vale la pena mirarlo?fuente
Otro enfoque que nadie ha mencionado es agregar buscadores que no distingan entre mayúsculas y minúsculas en ActiveRecord :: Base. Los detalles se pueden encontrar aquí . La ventaja de este enfoque es que no tiene que modificar todos los modelos, y no tiene que agregar la
lower()
cláusula a todas sus consultas que no distinguen entre mayúsculas y minúsculas, solo utiliza un método de buscador diferente.fuente
Las letras mayúsculas y minúsculas difieren solo en un bit. La forma más eficiente de buscarlos es ignorar este bit, no convertirlo en inferior o superior, etc. Vea las palabras clave
COLLATION
para MSSQL, veaNLS_SORT=BINARY_CI
si usa Oracle, etc.fuente
Find_or_create ahora está en desuso, debe usar una relación AR en su lugar más first_or_create, así:
Esto devolverá el primer objeto coincidente, o creará uno para usted si no existe ninguno.
fuente
La búsqueda sin distinción de mayúsculas y minúsculas viene incorporada con Rails. Da cuenta de las diferencias en las implementaciones de bases de datos. Utilice la biblioteca de Arel incorporada o una gema como Squeel .
fuente
Aquí hay muchas respuestas geniales, particularmente las de @ oma. Pero otra cosa que podría intentar es utilizar la serialización de columnas personalizada. Si no le importa que todo se almacene en minúsculas en su base de datos, puede crear:
Luego en tu modelo:
El beneficio de este enfoque es que aún puede usar todos los buscadores regulares (incluidos
find_or_create_by
) sin usar ámbitos personalizados, funciones o tenerlower(name) = ?
en sus consultas.La desventaja es que pierde información de la carcasa en la base de datos.
fuente
Similar a Andrews, que es el # 1:
Algo que funcionó para mí es:
Esto elimina la necesidad de hacer una
#where
y#first
en la misma consulta. ¡Espero que esto ayude!fuente
También puede usar ámbitos como este a continuación y ponerlos en duda e incluirlos en los modelos que pueda necesitar:
scope :ci_find, lambda { |column, value| where("lower(#{column}) = ?", value.downcase).first }
Luego use así:
Model.ci_find('column', 'value')
fuente
Suponiendo que usa mysql, puede usar campos que no distinguen entre mayúsculas y minúsculas: http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html
fuente
fuente
TypeError: Cannot visit Regexp
Algunas personas muestran usando LIKE o ILIKE, pero esas permiten búsquedas de expresiones regulares. Además, no es necesario minimizar en Ruby. Puede dejar que la base de datos lo haga por usted. Creo que puede ser más rápido. También
first_or_create
se puede usar despuéswhere
.fuente
Una alternativa puede ser
fuente
Hasta ahora, hice una solución usando Ruby. Coloque esto dentro del modelo del producto:
Esto me dará el primer producto donde coinciden los nombres. O nada.
fuente