2017-11-30 2 views
0

Ich habe eine Steuerung rufen Sie ein Modell für einen Benutzerpasswort Reset-Flow. Es ruft zwei Methoden:Nicht definierte Methode im Modell, aber andere Methode funktioniert

Controller

Password.new(@user) 
    .save_token_and_expiry 
    .email_reset 

Modell

module ModuleName 
    class Password 

    attr_accessor :token, :user 

    def initialize(user) 
     @token = SecureRandom.urlsafe_base64(ModuleName.configuration.reset_token_length, false) 
     @user = user 
    end 

    def save_token_and_expiry 
     User.find_by_email(@user['email']) 
     .update_attributes(password_reset_token: @token, password_token_expiry: ModuleName.configuration.password_token_expiry) 
    end 

    def email_reset 
     PasswordResetMailer.password_reset(@user, @token).deliver_now 
    end 
    end 
end 

Ausgang

NoMethodError (undefined method `email_reset' for true:TrueClass): 

Die erste davon erfolgreich ausgeführt wird, aber es nicht auf der zweiten.

Warum gibt die zweite Methode einen Fehler zurück?

+1

Sie kehren 'User' Objekt und versucht,' password' Methode auf, dass zu laufen Objekt, das nicht funktioniert –

Antwort

2

Ihre save_token_and_expiry Methode gibt true zurück, auf der Sie versuchen, email_reset Methode aufzurufen, die offensichtlich fehlschlägt. Wenn Sie wie diese Verkettungs zulassen möchten, können Sie save_token_and_expiry Methode Password Instanz zurückkehren machen, die sie aufgerufen wurde:

def save_token_and_expiry 
    User.find_by_email(@user['email']) 
     .update_attributes(password_reset_token: @token, password_token_expiry: ModuleName.configuration.password_token_expiry) 
    self 
end 
+0

Ah, das macht Sinn! Außerhalb des Umfangs der Frage, aber es fühlt sich an, als ob die Art und Weise, wie ich es geschrieben habe, nicht die beste Idee ist, da die Methodenaufrufe nun von der Reihenfolge abhängig sind. Gibt es vielleicht eine bessere Möglichkeit, diesen Anruf zu tätigen? – oneWorkingHeadphone

+0

Sie können die lokale Variable "password" festlegen und diese Methoden einfach in separaten Ausdrücken aufrufen, was ich wahrscheinlich empfehlen würde. –

0

Rails ist nicht so freundlich für die Verkettung Anrufe. save_token_and_expiry gibt Ihnen das Ergebnis der zuletzt aufgerufenen Aktion zurück (update_attributes) und update_attributes gibt Ihnen nicht das Ziel zurück, an dem es aufgerufen wurde, sondern einfach nur wahr/falsch. Deshalb hast du solche Fehler. Wenn Sie es beheben möchten, können Sie Ihre save_token_and_expiry Methode umschreiben als:

def save_token_and_expiry 
    User.find_by_email(@user['email']).update_attributes(password_reset_token: @token, password_token_expiry: ModuleName.configuration.password_token_expiry) 
    self 
end 
+1

Ich stimme dir nicht zu, dass Rails in dieser Hinsicht nicht freundlich ist. Der Rückgabewert 'true' /' false' gibt an, ob die Aktualisierung erfolgreich war oder nicht, und ist viel nützlicher als die Rückgabe des Datensatzes. Wann immer Sie die Aufzeichnung möchten, können Sie einfach darauf zugreifen, wie Sie es vorgeschlagen haben. Oder die Aufzeichnung im Erfolgsfall zurückgeben zu lassen und sonst nichts zu tun, könnte nützlicher sein. – sawa

+0

@sawa Wir sprechen über Vergleich. Im Vergleich zu jQuery ist es nicht benutzerfreundlich für die Verkettung. Ich denke nicht, dass es zu schade ist, ich denke nur darüber nach. – AntonTkachov

+1

Dem muss ich @sawa zustimmen. "Rails" ist eigentlich extrem Call-Chain-freundlich (denken Sie an QueryMethods können Sie 'where() sagen. where(). order(). limit(). where()'). Im Falle dieses Posts hat es nichts mit Schienen zu tun, sondern der OP-Code, der nicht kettenfreundlich ist. – engineersmnky

0

können Sie Controller-Code ändern:

@data = Password.new(@user) 
@data.save_token_and_expiry 
@data.email_reset 
Verwandte Themen