2009-07-27 5 views
36

Kurzes Beispiel: Ein Benutzer gibt einen Benutzernamen in ein Formular ein, und ich muss diesen Benutzernamen vor dem Speichern in der Datenbank der App eingeben, um ihn dauerhaft in Kleinbuchstaben umzuwandeln.Ruby on Rails - Kann ich Daten vor dem Speichern ändern?

Wo würde ich diesen Code speichern, und wie würde ich auf die Daten zugreifen, um in Kleinbuchstaben zu gelangen?

Danke.

Antwort

46

Sie eine von ActiveRecords Rückrufen in Ihrem User-Modell verwenden könnten, zum Beispiel so etwas wie die:

before_save { |user| user.username = user.username.downcase } 
+1

Weitere Informationen zu ActiveRecord Callbacks: http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html – Zargony

+1

Wenn Sie so viele Hooks haben und/oder viele Operationen an Attributen ausführen, können Sie auch Methoden für sie erstellen und geben die Methodennamen anstelle von Lambdas. Sie können auch [Attributfilter] (http://rubydoc.info/gems/attribute-filters/1.2.2/) sehen, das diesen Prozess vereinfacht, wenn Sie viele Callbacks haben, die Attribute ändern sollen. – siefca

0

Im allgemeinen Fall, der Submit-Button auf dem Formular eine Controller-Aktion delegieren sollte wo params [: Benutzername ist verfügbar. Sie könnten das klein schreiben, bevor Sie eine SomeModel.update (params) oder erstellen (params).

So könnten Sie es in der Controller-Aktion tun.

class User < ActiveRecord::Base 
    def username=(val) 
    write_attribute(:username, val.downcase) 
    end 
end 
+0

Sie müssen über die Konsequenzen der engen Kopplung von Controller und Modell nachdenken. Was passiert, wenn zwei Controller eine Instanz dieses Modells erstellen müssen? Was ist mit der Verwendung der Konsole, um einen Benutzer zu erstellen, und der Entwickler vergisst, dass die Benutzernamen downcase sein sollten? Was ist mit Komponententests? Ich denke, ein besserer Ansatz besteht darin, die ActiveRecord-Rückrufe zu verwenden, wie von effkay vorgeschlagen. –

+0

Ja, ich habe ihn auch neu eingestellt. Meine Argumentation: Solange es an einem Ort ist, kümmert es mich nicht wirklich. es sah nicht wirklich so aus, als gäbe es mehrere Stellen aus der OP-Frage ... also ging ich für die einfachste Sache, die möglicherweise funktionieren könnte. Auch haben Sie möglicherweise nicht immer ein Modell .. in diesem Szenario sieht es jedoch so aus, als ob das OP einen verwenden sollte. – Gishu

70

sollten Sie das Attribut Schreiber überschreiben. Dann wird garantiert, dass der Benutzername kleingeschrieben wird, egal, welcher Controller oder welche Aktion ihn erstellt. Wenn ein Problem auftritt, das eine Aktion innerhalb des Beobachters ausführt, wird eine Ausnahme ausgelöst und das Objekt wird nicht gespeichert.

Edit: Bitte beachten Sie, dass Sie nicht können eine Model.save innerhalb der before_save an dieses Modell gebunden, sonst enden Sie in einer Endlosschleife. Sie müssen ein update_attributes oder etwas tun.

+4

Ja, das ist die bessere Lösung. Es wird Konsistenz gewährleisten, bevor ein Objekt in der Datenbank gespeichert wird. – molf

+0

Danke hat mir sehr geholfen, ein Problem zu lösen, das mich ermüdete! :) – Vicer

+1

Diese Antwort sollte akzeptiert werden, verschieben Sie es an die Spitze! – RonLugge

0

würde ich vorschlagen, eine Methode Observer zum Modell und macht diese Aktion in der BEFORE_SAVE Zugabe:

11

In Ihrem Benutzermodell (Modelle/user.rb), nutzen Sie Active Rückrufe:

before_save do 
    self.username = self.username.downcase 
end 
+0

Dieses Ding funktioniert in meinem Fall – Neeraj

4

ich eine Weile verbrachte einen Fehler aufzublicken stoppen mich diesen Code von der Nutzung. Meine Datenbank wurde jedes Mal zurückgesetzt, wenn ich versuchte, ein Attribut abzufangen und es vor dem Speichern in false zu ändern.

Ich gebe meine Antwort hier, weil dieser Thread das erste Google-Ergebnis für die Durchführung dieser Aufgabe war, aber nicht das gesamte zurückgehende false Problem abgedeckt.

Wenn einer Ihrer Callbacks false zurückgibt, wird alles in der Datenbank zurückgesetzt.

Ich habe versucht, ein Angebot zu erstellen, um nicht in der Datenbank oder @offer.accepted = false akzeptiert werden. Das Problem war, dass diese Zeile dazu führte, dass die gesamte Methode false zurückgegeben und den gesamten Prozess zurückgesetzt wurde.

Ich reparierte sie durch true danach in einer impliziten Rückkehr warf

Code, arbeitete:

before_save {|offer| offer.accepted = false; true}

Imbiss: Ihre Rückrufe nicht false zurückkehren können, wenn Sie wollen, um erfolgreich zu sein.

Quelle: rails 3 : Do i need to give return true in a before_save callback for an object.save to work?

1
def username=(str) 
super(str.downcase) 
end 

Ich dachte, das viel einfacher.