2015-06-10 10 views
7

Questo codice è fornito come esempio per l'uso con devise e OmniAuth, funziona in my project.Perché single `=` funziona nell'istruzione `if`?

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 

Non so perché è un unico segno di uguale come apposto ad un doppio segno di uguale, che ho pensato che era necessario per if -statements. Il mio IDE "intelliJ IDEA" concorda con le mie preoccupazioni.

risposta

7

L'unica cosa necessaria affinché una dichiarazione if sia valida è un'espressione booleana. In questo caso, poiché = restituisce il risultato del compito, ciò che viene effettivamente testato è la falsità di session["devise.facebook_data"].

IntelliJ ha un buon motivo per presentare un reclamo su codice come questo, in quanto è difficile da leggere senza sapere una cosa o due su Ruby. Una raccomandazione sarebbe quella di spostarlo in una dichiarazione di assegnazione esplicita. Questo ha il vantaggio di ESSERE un riferimento ad esso due volte.

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

Grazie !! Ha senso ora, l'hai spiegato perfettamente. – thesowismine

+0

Non sai cosa intendi per "cosa necessaria ... essere valido è un'espressione booleana". Qualsiasi oggetto può apparire dopo "if". C'è qualche oggetto "non-booleano" che hai in mente che renderebbe illegale una condizione "if"? – sawa

+0

@sawa Quando sono vicino a una macchina posso rivedere quella parte. – Makoto

2

In Ruby, un segno di uguale uguale viene utilizzato per l'assegnazione . L'espressione

data = session["devise.facebook_data"] 

assegna il risultato della valutazione session["devise.facebook_data"] a una variabile locale chiamata data.

Se l'hash session non dispone di una chiave "devise.facebook_data", tornerà nil e data verrà assegnato nil. Le assegnazioni valutano il valore assegnato, quindi l'assegnazione verrà valutata anche su nil. nil è considerato falso in un contesto booleano, pertanto l'operando destro di && non verrà valutato. In questo modo, non riceverai un NoMethodError cercando di chiamare nil["extra"]["raw_info"].

Se il session hash fa avere una chiave "devise.facebook_data", data sarà impostato il valore ad essa associato. Qualsiasi valore diverso da nil e false è considerato attendibile, pertanto verrà valutato l'operando di destra dell'operatore &&.

Se la condizione è attendibile, verrà valutata la clausola then, che utilizza la variabile data assegnata nella condizione.


Nota: Credo che si potrebbe anche utilizzare la variabile data all'interno del lato destro dell'operatore &&, vale a dire la condizione potrebbe leggere in questo modo invece:

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

ma dovrò per controllare quello

+0

Sì, questo è quello che ho pensato, immagino che sia solo confuso dal layout della funzione. Potresti spiegare che cosa esattamente sta chiedendo? Vedo il &&, ma sembra che ci sia di più? – thesowismine

+0

Il primo 'if' è equivalente a' data = ... 'seguito da' if data; user.email = ... '. –

1

Un operatore di assegnazione (=) restituisce il valore assegnato, che viene quindi valutato da if. Nel ruby, solo false e nil sono considerati come false. Tutto il resto viene valutato su true in un contesto booleano (ad esempio if).

0

Ruby non si preoccupa dei tipi di condizionali, a differenza di Java. Finché il valore non è né nullo né falso, passerà.

Nel tuo esempio si discrimina in realtà contro nil: il condizionale if garantisce che i dati effettivamente esistano e non siano nulli, quindi possiamo usarli, assumendo che si tratti di un hash. Questo è un modello comune in Ruby.

+0

In realtà, indipendentemente dal fatto che un valore sia falesy o no ** è determinato dal suo tipo (classe) **, cioè, se è un'istanza di 'NilClass' o' FalseClass', allora è falesy. – sawa