2010-11-13 13 views
12

Attualmente sto passando attraverso un tutorial RoR (http://railstutorial.org/chapters/sign-in-sign-out#sec:signin_success è la sezione pertinente) che sembra essere abbastanza buono, anche se ho incontrato il seguente problema quando si tenta di visualizzare il sito di esempio .variabile locale indefinita o metodo 'current_user'

Extracted source (around line #10): 

7:   <li><%= link_to "Home", root_path %></li> 
8:   <li><%= link_to "About", about_path %></li> 
9:   
10:    <% if signed_in? %> 
11:     <li><%= link_to "Profile", current_user %></li> 
12:     <li><%= link_to "Sign out", signout_path, :method => delete %></li> 
13:    <% else %> 

Come si può vedere, il problema deriva dal mio metodo "signed_in?" che dovrebbe controllare se l'utente si è connesso o meno controllando se la variabile current_user è impostata (ho incluso il resto del codice dal supporto per dare un contesto, scuse):

module SessionsHelper 

    def sign_in(user) 
    cookies.permanent.signed[:remember_token] = [user.id, user.salt] 
    current_user = user 
    end 

    def sign_out 
    cookies.delete[:remember_token] 
    current_user = nil 
    end 

    def current_user= (user) 
    @current_user ||= user_from_remember_token 
    end 

    def signed_in? 
    !current_user.nil? 
    end 

    private 

    def user_from_remember_token 
     User.authenticate_with_salt(*remember_token) 
    end 

    def remember_token 
     cookies.signed[:remember_token] || [nil, nil] 
    end 

end 

Da la mia comprensione, .nil? è un metodo che controlla se un oggetto è stato definito o meno e quindi l'oggetto non definito non dovrebbe generare un errore ma piuttosto restituire falso? Ho cercato il tutorial per tutti i casi di current_user (prima di verificare se qualcun altro ha avuto questo problema con scarso successo) e il mio codice sembra corretto quindi sono un po 'confuso e se qualcuno è in grado di aiutarmi a capire il modo in cui le variabili di Ruby sono dovrebbe essere accessibile e perché il mio codice non funziona sarei molto grato.

Edit:

non sono sicuro se è importante campo di applicazione Sto solo cominciando sia Rails e Ruby, ma la SessionsHelper helper è utilizzato da mio controller Utenti e vista (è incluso nelle mie applicazioni controller)

risposta

7

Mi sono imbattuto in questo stesso numero & per lo stesso motivo. Hai trascurato parte delle istruzioni sul 'Listato 9.16'.

def current_user= (user) 
    @current_user ||= user_from_remember_token 
end 

Si supponeva che si sarebbe dovuto modificare quanto segue.

def current_user 
    @current_user ||= user_from_remember_token 
end 

Dovrai anche modificare tutte le istanze di * self. * Current_user in * @ * current_user.

Una volta eseguita l'operazione, gli errori vengono risolti.

2

Il nullo? il metodo non sta andando a controllare se una variabile o un metodo è definito. Sta solo controllando se è definito come un oggetto nullo o meno. Ruby risalta la catena degli antenati per SessionsHelper e infine determina che current_user non è definito da nessuna parte (finirà con il metodo # method_missing) e quindi genera un errore. Il modo più veloce per risolvere il problema sarebbe:

#app/helpers/sessions_helper.rb 
def current_user 
    @current_user ||= false 
end 
+0

o credo che si possa fare "@current_user || = user_from_remember_token || false" se si desidera essere più in linea con il codice corrente. – JackCA

+0

Mentre questo sicuramente ferma l'errore, restituisce costantemente false. Immagino sia possibile che possa esserci un problema con i miei metodi di firma che non rendono mai attuale un utente corrente, quindi probabilmente è meglio per me dargli un'occhiata dopo una buona notte di sonno. – djlumley

2

ho chiesto ad un amico, e ha corretto i miei errori. Penso che gran parte del mio errore derivasse dal non aver completamente familiarizzato con la portata variabile in Ruby e dimenticare che tutto è un oggetto e quindi il metodo current_user = (utente) stava sovrascrivendo la funzione di assegnazione.

La soluzione del mio amico era quella di cambiare l'ambito di current_user in una variabile istanziata (quindi può essere utilizzata correttamente) e cambiare la funzione curent_user = (utente) in una semplice funzione get_current_user per determinare se l'utente corrente esiste nel cookie.

Il codice modificato finale è il seguente:

#app/helpers/sessions_helper.rb 

    def sign_in(user) 
    cookies.permanent.signed[:remember_token] = [user.id, user.salt] 
    @current_user = user 
    end 

    def sign_out 
    cookies.delete(:remember_token) 
    @current_user = nil 
    end 

    def get_current_user 
    @current_user ||= user_from_remember_token 
    end 

    def signed_in? 
    !get_current_user.nil? 
    end 

#app/views/layouts/_header.erb 
<% if signed_in? %> 
       <li><%= link_to "Profile", get_current_user %></li> 
       <li><%= link_to "Sign out", signout_path, :method => :delete %></li> 
      <% else %> 
       <li><%= link_to "Sign in", signin_path %></li> 
      <% end %> 

Come si può vedere la variabile nel mio header parziale è stato cambiato per riflettere il metodo utilizzato nella helper per ottenere l'utente.

intenzione di iniziare la lettura di alcuni di Ruby di base guide così la prossima volta che ricevo in sopra la mia testa ho un'idea di dove cominciare fissandola :)

+1

Una best practice per l'autorizzazione di Rails sarebbe quella di denominare il metodo current_user anziché get_current_user e definire un metodo current_user? che controlla se current_user è nullo o no. È un modello molto comune. –

+0

C'è una ragione particolare per quello? O è, come sembra la maggior parte delle Rails, solo perché è così che le persone lo fanno? Vedo un aumento della leggibilità, mi chiedo solo se c'è un altro motivo che mi manca. – djlumley

+0

Non è solo una cosa di Rails. La convenzione Ruby per getter e setter è attribute_name() e attribute_name =(). La possibilità di aggiungere? i nomi dei metodi erano intenzionali in modo che gli sviluppatori potessero formulare domande coerenti. Ruby è progettato per essere il più colloquiale possibile. –

4

Assicurarsi di avere il seguente codice nella SessionHelper

def current_user=(user) 
    @current_user = user 
end 

def current_user 
    @current_user ||= user_from_remember_token 
end 
Problemi correlati