2010-03-12 2 views
5

Ich möchte in der Lage sein Artist.case_insensitive_find_or_create_by_name(artist_name) zu tun [1] (und es haben arbeiten sowohl auf SQLite und PostgreSQL)Case-unempfindlichen find_or_create_by_whatever

Was ist der beste Weg, dies zu erreichen? Im Moment ist ich einfach nur mit einer Methode direkt an die Artist Klasse (Art hässlich, vor allem, wenn ich diese Funktion in einer anderen Klasse will, aber was auch immer):

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

[1]: Nun, im Idealfall wäre es Artist.find_or_create_by_name(artist_name, :case_sensitive => false), aber das scheint viel schwieriger zu implementieren

+0

Warum ist 'Artist.find_or_create_by_name (artist_name,: case_sensitive => false)' schwerer zu implementieren? –

+1

Wenn Sie MySQL verwenden, wird bei Übereinstimmung nicht zwischen Groß- und Kleinschreibung unterschieden. –

+0

@KandadaBoggu weil 'find_or_create_by_name' dynamisch von' method_missing' erzeugt wird? Vielleicht ist es nicht schwieriger - wie würdest du es umsetzen? –

Antwort

7

Diese Antwort ist für die zusätzliche Fragen in der Frage Kommentaren gefragt.

Sie können den Standardnamen find_or_create_by_name nicht aufrufen, wenn Sie diese Methode überschreiben. Aber Sie können Ihre eigenen, wie unten gezeigt implementieren:

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 

Jetzt können Sie die überschriebene Methode wie folgt aufrufen:

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

Über dieses Thema gesprochen here. Niemand war in der Lage, eine bessere Lösung als Ihre zu finden :)

5

Sie müssen einen Index basierend auf der Datenbank erstellen.

postgreSQL

erstellen Kleinbuchstaben Index auf artist_name Spalte.

CREATE INDEX lower_artists_name ON artists(lower(artist_name)) 

mySQL

Suchen Groß- und Kleinschreibung

SQLLite

erstellen Index auf artist_name Spalte mit collate Parameter

CREATE INDEX lower_artists_name ON artists(artist_name collate nocase) 

Jetzt können Sie find_or_create in einer DB-unabhängigen Art und Weise verwenden:

find_or_create_by_artist_name(lower(artist_name)) 

Referenz

PostgreSQL: Case insensitive search

sqlLite: Case insensitive search

10

Rails 4 gibt Ihnen einen Weg, um das Gleiche zu erreichen:

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

+0

Klingt wie diese Methode noch in Schienen 4.2 existiert, aber ist veraltet. – Jared

+1

Es sieht aus, als ob es immer noch in Rails 5.0 funktioniert, ohne irgendwelche Verwarnungen. Wo haben Sie gesehen, dass die Methode veraltet ist? –

+0

Mein schlechtes, du hast Recht. Ich dachte nur, dass es veraltet war, da ich es in der Dokumentation nicht finden konnte. Stellt sich heraus, es ist nur undokumentiert. – Jared