2010-03-12 14 views
5

Voglio essere in grado di fare Artist.case_insensitive_find_or_create_by_name(artist_name) [1] (e farlo lavorare su entrambi SQLite e PostgreSQL)Case-insensitive find_or_create_by_whatever

Qual è il modo migliore per ottenere questo risultato? In questo momento sto solo l'aggiunta di un metodo direttamente al Artist di classe (una specie di brutto, soprattutto se voglio questa funzionalità in un'altra classe, ma qualunque cosa):

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

[1]: Beh, idealmente sarebbe Artist.find_or_create_by_name(artist_name, :case_sensitive => false), ma questo sembra molto più difficile da implementare

+0

Perché "Artista.find_or_create_by_name (artist_name,: case_sensitive => false)" è più difficile da implementare? –

+1

Se si utilizza MySQL, le corrispondenze non fanno distinzione tra maiuscole e minuscole. –

+0

@KandadaBoggu perché 'find_or_create_by_name' viene creato dinamicamente da' method_missing'? Forse non è più difficile - come lo implementeresti? –

risposta

7

Questa risposta è per le ulteriori domande poste nei commenti questione.

Non è possibile chiamare il valore predefinito find_or_create_by_name se si esegue l'override di tale metodo. Ma è possibile implementare il proprio come illustrato di seguito:

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 

Ora è possibile chiamare il metodo override come segue:

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

Parlato di questo here. Nessuno è stato in grado di trovare una soluzione migliore della tua :)

5

Devi creare un indice basato sul database.

postgreSQL

creare un indice minuscolo su artist_name colonna.

CREATE INDEX lower_artists_name ON artists(lower(artist_name)) 

mySQL

Ricerche sono case insensitive

SqlLite

Creare un indice artist_name colonna con il parametro di fascicolazione

CREATE INDEX lower_artists_name ON artists(artist_name collate nocase) 

Ora è possibile utilizzare find_or_create in maniera indipendente DB:

find_or_create_by_artist_name(lower(artist_name)) 

Riferimento

PostgreSQL: Case insensitive search

sqlLite: Case insensitive search

10

Rails 4 ti dà un modo per ottenere la stessa cosa:

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

+0

Sembra che questo metodo esista ancora nelle rotaie 4.2 ma è deprecato. – Jared

+1

Sembra che funzioni ancora su rail 5.0 senza alcun avviso di deprecazione. Dove hai visto che il metodo è stato deprecato? –

+0

Il mio male, hai ragione. Ho pensato che fosse deprecato poiché non riuscivo a trovarlo nella documentazione. Si scopre che è solo non documentato. – Jared