2015-06-10 5 views
7

Dieser Code wird als Beispiel für die Verwendung mit Devise und OmniAuth bereitgestellt. Er funktioniert in my project.Warum funktioniert Single `=` in `if` Anweisung?

class User < ActiveRecord::Base 
    def self.new_with_session(params, session) 
    super.tap do |user| 
     if data = session["devise.facebook_data"] && session["devise.facebook_data"]["extra"]["raw_info"] 
     user.email = data["email"] if user.email.blank? 
     end 
    end 
    end 
end 

Ich weiß nicht, warum es eine einzige equals ist als apposed anmelden, um ein doppeltes Gleichheitszeichen, das dachte ich für if -Aussagen notwendig war. Meine IDE "intelliJ IDEA" stimmt meinen Bedenken zu.

Antwort

7

Die einzige notwendige Sache für eine if-Anweisung, um gültig zu sein, ist ein boolescher Ausdruck. In diesem Fall, da = das Ergebnis der Zuweisung zurückgibt, wird tatsächlich die Falschheit von session["devise.facebook_data"] getestet.

IntelliJ hat einen guten Grund, eine Beschwerde über Code wie diesen einzureichen, da er schwer zu lesen ist, ohne etwas über Ruby zu wissen. Eine Empfehlung wäre, das stattdessen in eine explizite Zuweisungsanweisung zu verschieben. Dies hat den zusätzlichen Vorteil, dass zweimal eine Referenz auf DRY erstellt wird.

class User < ActiveRecord::Base 
    def self.new_with_session(params, session) 
    super.tap do |user| 
     data = session["devise.facebook_data"] 
     if data && data["extra"]["raw_info"] 
     user.email = data["email"] if user.email.blank? 
     end 
    end 
    end 
end 
+0

Danke !! Macht jetzt Sinn, das hast du perfekt erklärt. – thesowismine

+0

Nicht sicher, was Sie mit "notwendiges Ding ... gemeint zu sein, ist ein boolescher Ausdruck." Jedes Objekt kann nach "if" erscheinen. Gibt es ein "nicht-boolesches" Objekt, das Sie im Sinn haben und das eine "if" -Bedingung illegal machen würde? – sawa

+0

@sawa Wenn ich in der Nähe einer Maschine bin, kann ich diesen Teil überarbeiten. – Makoto

2

In Ruby wird ein einzelnes Gleichheitszeichen für Zuweisung verwendet. Der Ausdruck

data = session["devise.facebook_data"] 

weist das Ergebnis der datasession["devise.facebook_data"] auf eine lokale Variable mit dem Namen auswertet.

Wenn der session Hash keinen "devise.facebook_data" Schlüssel hat, wird er zurückkehren nil und data wird nil zugeordnet werden. Zuordnungen werden zum zugewiesenen Wert ausgewertet, daher wird die Zuweisung auch auf ausgewertet. nil wird in einem booleschen Kontext als falsch betrachtet, daher wird der rechte Operand von && nicht ausgewertet. Auf diese Weise erhalten Sie keine NoMethodError versuchen, nil["extra"]["raw_info"] anrufen.

Wenn der session Hash tut einen "devise.facebook_data" Schlüssel, data wird auf den Wert gesetzt werden, damit verbunden. Jeder andere Wert als nil und false wird als truthy betrachtet, daher wird der rechte Operand des Operators && ausgewertet.

Wenn die Bedingung truthy ist, wird die then Klausel ausgewertet, die die in der Bedingung zugewiesene data Variable verwendet.


Hinweis: Ich glaube, dass man auch die data Variable innerhalb der rechten Seite des && Operator verwenden könnte, dh die Bedingung wie diese statt lesen:

if data = session["devise.facebook_data"] && data["extra"]["raw_info"] 

Aber ich werde haben um das zu überprüfen.

+0

Ja, das ist, was ich dachte, ich denke, ich bin nur verwirrt durch das Layout der Funktion. Könntest du vielleicht erklären, was genau das fragt? Ich sehe das &&, aber es scheint als wäre es mehr als das? – thesowismine

+0

Das erste 'if' ist äquivalent zu' data = ... 'gefolgt von' if data; user.email = ... '. –

1

Ein Zuweisungsoperator (=) gibt den zugewiesenen Wert zurück, der dann von if ausgewertet wird. In Rubin werden nur false und nil als false betrachtet. Alles andere ergibt true in einem booleschen Kontext (wie ein if).

0

Ruby interessiert sich im Gegensatz zu Java nicht für Typen in Bedingungen. Solange der Wert weder Null noch Falsch ist, wird er übergeben.

In Ihrem Beispiel diskriminieren Sie tatsächlich gegen Null: Das if conditionnal stellt sicher, dass Daten tatsächlich existieren und nicht null sind, also können wir es verwenden, vorausgesetzt, es ist ein Hash. Dies ist ein übliches Muster in Ruby.

+0

Tatsächlich wird, ob ein Wert falesy oder nicht ** ist, durch seinen Typ (Klasse) ** bestimmt, d. H. Wenn es eine Instanz von "NilClass" oder "FalseClass" ist, dann ist es falesy. – sawa

Verwandte Themen