tutorial postgres español database_url app ruby-on-rails postgresql rails-postgresql unaccent

ruby-on-rails - español - heroku postgres tutorial



Postgres no acentuó la búsqueda de LIKE en Rails 3.1 en Heroku (5)

¿Cómo puedo modificar una condición donde / como en una consulta de búsqueda en Rails?

find(:all, :conditions => ["lower(name) LIKE ?", "%#{search.downcase}%"])

¿De modo que los resultados se combinan independientemente de los acentos? (ej. métro = metro). Debido a que estoy usando utf8, no puedo usar "to_ascii". La producción se está ejecutando en Heroku.


La solución del hombre pobre.

Si puedes crear una función, puedes usar esta. Compilé la lista comenzando here y la agregué con el tiempo. Es bastante completo. Es posible que incluso desee eliminar algunos caracteres:

CREATE OR REPLACE FUNCTION lower_unaccent(text) RETURNS text AS $func$ SELECT lower(translate($1 , ''¹²³áàâãäåāăąÀÁÂÃÄÅĀĂĄÆćčç©ĆČÇĐÐèéêёëēĕėęěÈÊËЁĒĔĖĘĚ€ğĞıìíîïìĩīĭÌÍÎÏЇÌĨĪĬłŁńňñŃŇÑòóôõöōŏőøÒÓÔÕÖŌŎŐØŒř®ŘšşșߊŞȘùúûüũūŭůÙÚÛÜŨŪŬŮýÿÝŸžżźŽŻŹ'' , ''123aaaaaaaaaaaaaaaaaaacccccccddeeeeeeeeeeeeeeeeeeeeggiiiiiiiiiiiiiiiiiillnnnnnnooooooooooooooooooorrrsssssssuuuuuuuuuuuuuuuuyyyyzzzzzz'' )); $func$ LANGUAGE sql IMMUTABLE;

Tu consulta debería funcionar así:

find(:all, :conditions => ["lower_unaccent(name) LIKE ?", "%#{search.downcase}%"])

Para búsquedas ancladas a la izquierda, puede utilizar un índice en la función para obtener resultados muy rápidos:

CREATE INDEX tbl_name_lower_unaccent_idx ON fest (lower_unaccent(name) text_pattern_ops);

Para consultas como:

SELECT * FROM tbl WHERE (lower_unaccent(name)) ~~ ''bob%''

Solución adecuada

En PostgreSQL 9.1+ , con los privilegios necesarios, puedes simplemente:

CREATE EXTENSION unaccent;

que proporciona una función unaccent() , haciendo lo que necesita (excepto por lower() , simplemente use esa función adicional si es necesario). Lea el manual sobre esta extensión .
También disponible para PostgreSQL 9.0, pero la sintaxis CREATE EXTENSION es nueva en 9.1.

Más sobre los no acentos y los índices:


Asumiendo que Foo es el modelo contra el que está buscando y name es la columna. Combinando la translate Postgres y la translate ActiveSupport. Puedes hacer algo como:

Foo.where( "translate( LOWER(name), ''âãäåāăąÁÂÃÄÅĀĂĄèééêëēĕėęěĒĔĖĘĚìíîïìĩīĭÌÍÎÏÌĨĪĬóôõöōŏőÒÓÔÕÖŌŎŐùúûüũūŭůÙÚÛÜŨŪŬŮ'', ''aaaaaaaaaaaaaaaeeeeeeeeeeeeeeeiiiiiiiiiiiiiiiiooooooooooooooouuuuuuuuuuuuuuuu'' ) LIKE ?", "%#{ActiveSupport::Inflector.transliterate("%qué%").downcase}%" )


En primer lugar, instale postgresql-contrib. Luego te conectas a tu DB y ejecutas:

CREATE EXTENSION unaccent;

para habilitar la extensión para su base de datos.

Dependiendo de su idioma, es posible que necesite crear un nuevo archivo de reglas (en mi caso greek.rules , ubicado en /usr/share/postgresql/9.1/tsearch_data ), o simplemente adjuntar a las unaccent.rules existentes (bastante sencillas).

En caso de que cree su propio archivo .rules , debe hacerlo por defecto:

ALTER TEXT SEARCH DICTIONARY unaccent (RULES=''greek'');

Este cambio es persistente, por lo que no es necesario rehacerlo.

El siguiente paso sería agregar un método a un modelo para hacer uso de esta función.

Una solución simple sería definir una función en el modelo. Por ejemplo:

class Model < ActiveRecord::Base [...] def self.unaccent(column,value) a=self.where(''unaccent(?) LIKE ?'', column, "%value%") a end [...] end

Entonces, simplemente puedo invocar:

Model.unaccent("name","text")

Invocar el mismo comando sin la definición del modelo sería tan simple como:

Model.where(''unaccent(name) LIKE ?'', "%text%"

Nota: El ejemplo anterior ha sido probado y funciona para postgres9.1, Rails 4.0, Ruby 2.0.

ACTUALIZAR INFORMACIÓN
Se corrigió el posible backdoor SQLi gracias a los comentarios de @Henrik N


Hay 2 preguntas relacionadas con su búsqueda en el StackExchange: https://serverfault.com/questions/266373/postgresql-accent-diacritic-insensitive-search

Pero como usted está en Heroku, dudo que este sea un buen partido (a menos que tenga un plan de base de datos dedicado).

También hay este en SO: Eliminación de acentos / signos diacríticos de la cadena al tiempo que se conservan otros caracteres especiales .

Pero esto supone que sus datos se almacenan sin ningún acento.

Espero que te apunte en la dirección correcta.


Para aquellos que, como yo, que tienen problemas para agregar la extensión unaccent para PostgreSQL y hacer que funcione con la aplicación Rails, aquí está la migración que necesita crear:

class AddUnaccentExtension < ActiveRecord::Migration def up execute "create extension unaccent" end def down execute "drop extension unaccent" end end

Y, por supuesto, después de rake db:migrate , podrá usar la función unaccent en sus consultas: unaccent(column) similar to ... o unaccent(lower(column)) ...