2010-11-13 10 views
12

Actualmente estoy asistiendo a un tutorial de RoR (http://railstutorial.org/chapters/sign-in-sign-out#sec:signin_success es la sección relevante) que parece ser bastante bueno, aunque me he encontrado con el siguiente problema al intentar ver el sitio de muestra .variable local indefinida o método 'usuario_actual'

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 %> 

Como puede ver, el problema se deriva de mi método "signed_in?" que se supone que comprobar si el usuario ha iniciado sesión o no comprobando si se establece la variable current_user (He incluido el resto del código del ayudante para dar un contexto, disculpas):

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 

De mi entendimiento, .nil? ¿Es un método que verifica si un objeto ha sido o no definido y, por lo tanto, el objeto no definido no debería generar un error, sino devolver falso? Busqué en el tutorial todos los casos de current_user (antes de verificar si alguien más tuvo este problema con poco éxito) y mi código parece correcto, así que estoy un poco confundido y si alguien puede ayudarme a entender la forma en que las variables de Ruby son se supone que se debe acceder y por qué mi código no funciona, estaría muy agradecido.

Editar:

No estoy seguro de si es importante con el alcance que sólo estoy empezando ambos rieles y Ruby, sin embargo, el SessionsHelper ayudante está siendo utilizado por mi controlador de usuarios y puntos de vista (que está incluido en mis aplicaciones controlador)

Respuesta

7

Me encontré con este mismo problema & fue por la misma razón. Pasó por alto parte de las instrucciones en 'Listado 9.16'.

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

Se suponía que debía cambiar esto a lo siguiente.

def current_user 
    @current_user ||= user_from_remember_token 
end 

También deseará cambiar todas las instancias de * self. * Current_user a * @ * current_user.

Una vez que hace esto, se resuelven los errores.

2

¿El nil? método no va a verificar si una variable o método está definido. Solo se verifica si se define como un objeto nulo o no. Ruby sube la cadena de ancestros para SessionsHelper y finalmente determina que current_user no está definido en ningún lado (eventualmente terminará en Kernel # method_missing) y luego arroja un error. La forma más rápida de resolver el problema sería:

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

o creo que podría hacer "@current_user || = user_from_remember_token || false" si quiere estar más en línea con su código actual. – JackCA

+0

Si bien eso ciertamente detiene el error, constantemente devuelve falso. Supongo que es posible que haya un problema con mis métodos de inicio de sesión que hacen que un usuario_actual nunca se defina, por lo que probablemente sea mejor que lo vea después de una buena noche de sueño. – djlumley

2

le pregunté a un amigo, y corregir mis errores. Creo que una gran parte de mi error vino de no estar completamente familiarizado con el alcance variable en Ruby y olvidar que todo es un objeto y, por lo tanto, el método current_user = (usuario) estaba anulando la función de asignación.

La solución de mi amigo fue cambiar el alcance de current_user a una variable instanciada (para que pueda ser utilizado correctamente) y cambiar la función curant_user = (usuario) a una simple función get_current_user para determinar si el usuario actual existe en la galleta

El código modificado final es la siguiente:

#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 %> 

Como se puede ver la variable en mi cabecera parcial también se ha cambiado para reflejar el método utilizado en la ayuda para obtener el usuario.

va a empezar a leer algunos de Ruby básica guías así que la próxima vez que tengo en mi cabeza tengo una idea de por dónde empezar fijándolo :)

+1

Una práctica recomendada para la autorización de Rails sería nombrar el método current_user en lugar de get_current_user y definir un método current_user? que verifica si current_user es nulo o no. Es un patrón muy común. –

+0

¿Hay alguna razón en particular para eso? ¿O es, como la mayoría de las cosas de Rails parecen ser, simplemente porque así es como lo hace la gente? Puedo ver un aumento de la legibilidad, solo me pregunto si hay otra razón por la que me estoy perdiendo. – djlumley

+0

No es solo una cosa de Rails. La convención de Ruby para getters y setters es attribute_name() y attribute_name =(). La capacidad de agregar? a los nombres de métodos fue intencional para que los desarrolladores pudieran formar preguntas coherentes. Ruby está diseñado para ser tan conversacional como sea posible. –

4

Asegúrese de que tiene el código siguiente en el SessionHelper

def current_user=(user) 
    @current_user = user 
end 

def current_user 
    @current_user ||= user_from_remember_token 
end 
Cuestiones relacionadas