2010-03-12 12 views
5

Quiero ser capaz de hacer Artist.case_insensitive_find_or_create_by_name(artist_name) [1] (para que funcionen tanto en SQLite y PostgreSQL)Caso insensible find_or_create_by_whatever

Cuál es la mejor manera de lograr esto? En este momento estoy simplemente añadiendo un método directamente al Artist clase (clase de feo, especialmente si quiero esta funcionalidad en otra clase, pero lo que sea):

def self.case_insensitive_find_or_create_by_name(name) 
    first(:conditions => ['UPPER(name) = UPPER(?)', name]) || create(:name => name) 
    end 

[1]: Bueno, lo ideal sería Artist.find_or_create_by_name(artist_name, :case_sensitive => false), pero esto parece mucho más difícil de implementar

+0

¿Por qué 'Artist.find_or_create_by_name (artist_name,: case_sensitive => false)' es más difícil de implementar? –

+1

Si tuviera que usar MySQL, las coincidencias no distinguen entre mayúsculas y minúsculas. –

+0

@KandadaBoggu porque 'find_or_create_by_name' se crea dinámicamente por' method_missing'? Tal vez no sea más difícil, ¿cómo lo implementarías? –

Respuesta

7

Esta respuesta es para las preguntas planteadas en los comentarios de interrogación.

No podrá llamar al predeterminado find_or_create_by_name si anula ese método. Pero se puede implementar su propio como se muestra a continuación:

def self.find_or_create_by_name(*args) 
    options = args.extract_options! 
    options[:name] = args[0] if args[0].is_a?(String) 
    case_sensitive = options.delete(:case_sensitive) 
    conditions = case_sensitive ? ['name = ?', options[:name]] : 
           ['UPPER(name) = ?', options[:name].upcase] 
    first(:conditions => conditions) || create(options) 
end 

Ahora se puede llamar al método reemplazado como sigue:

User.find_or_create_by_name("jack") 
User.find_or_create_by_name("jack", :case_sensitive => true) 
User.find_or_create_by_name("jack", :city=> "XXX", :zip => "1234") 
User.find_or_create_by_name("jack", :zip => "1234", :case_sensitive => true) 
1

Habló de esto here. Nadie fue capaz de encontrar una solución mejor que la tuya :)

5

Tienes que crear un índice basado en la base de datos.

PostgreSQL

crear un índice más bajo en caso artist_name columna.

CREATE INDEX lower_artists_name ON artists(lower(artist_name)) 

mySQL

Búsquedas son sensibles a mayúsculas

SqlLite

Crear un índice en artist_name columna con el parámetro de intercalación

CREATE INDEX lower_artists_name ON artists(artist_name collate nocase) 

Ahora puede utilizar find_or_create de manera independiente DB:

find_or_create_by_artist_name(lower(artist_name)) 

Referencia

PostgreSQL: Case insensitive search

sqlLite: Case insensitive search

10

Carriles 4 le da una manera de lograr lo mismo:

Artist.where('lower(name) = ?', name.downcase).first_or_create(:name=>name)

+0

Parece que este método todavía existe en los rieles 4.2 pero está en desuso. – Jared

+1

Parece que todavía funciona en rieles 5.0 sin advertencias de desaprobación. ¿Dónde viste que el método estaba en desuso? –

+0

Malo, estás en lo cierto. Solo pensé que estaba obsoleto porque no pude encontrarlo en la documentación. Resulta que simplemente no está documentado. – Jared

Cuestiones relacionadas