2010-01-17 16 views
8

Una cosa que puedes hacer en mi rap lyric explanation site es "como" explicaciones (una vez que está conectado):Solicitar que el usuario para iniciar sesión después de que toma una determinada acción

http://dl.getdropbox.com/u/2792776/screenshots/2010-01-17_1645.png

me gustaría muestre los enlaces "Me gusta" a los usuarios que no hayan iniciado sesión y luego, cuando un usuario que no haya iniciado sesión haga clic en "Me gusta", muéstrele un lightbox con un formulario "Iniciar sesión o registrarse" (como Digg/Reddit)

http://dl.getdropbox.com/u/2792776/screenshots/2010-01-17_1650.png

¿Cuál es la mejor manera de lograr t ¿su?

Actualmente estoy usando este enfoque:

  1. Al hacer clic en "Me gusta" Puestos a /annotations/:id/vote (el cuerpo de POST indica si el usuario es gusto o "unliking").
  2. La acción del controlador vote anotación tiene un require_userbefore_filter que tiene este aspecto:

    def require_user 
        unless current_user 
        store_desired_location 
        flash[:notice] = "You'll need to login or register to do that" 
        redirect_to login_path # map.login '/login', :controller => 'user_sessions', :action => 'new' 
        return false 
        end 
    end 
    
  3. user_sessions#new se parece a esto:

    def new 
        @user_session = UserSession.new 
        respond_to do |format| 
        format.html {} 
        format.js { 
         render :layout => false 
        } 
        end 
    end 
    

El problema es que la redirección no lo hace parece que funciona correctamente en javascript:

http://dl.getdropbox.com/u/2792776/screenshots/2010-01-17_1700.png

¿Cómo hago esto para redireccionar correctamente?

Además, ¿es este el enfoque general correcto? Otro pensamiento que tuve fue adjuntar un manejador diferente a los enlaces "Me gusta" en JavaScript cuando no había un usuario conectado (pero no creo que este método se adapte bien a otras acciones que me gustaría manejar de la misma manera)

Respuesta

3

Aquí hay algunos problemas que superar.

  1. Los navegadores en general no permiten el redireccionamiento a una solicitud POST.

  2. redirect_to no conserva el formato sin entrada adicional.

  3. La ubicación de la tienda no conserva los datos del formulario.

Todos estos problemas se pueden resolver eliminando los redireccionamientos.

Aquí es cómo he entregué en el pasado:

En lugar de redirigir en required_user, render. Si un filtro anterior redirige o representa la acción pendiente se cancela. (No es necesario que devuelva falso tampoco). Desafortunadamente, esta ruta borra los límites del controlador. Pero permite un repliegue html simple y se presta a DRYness.

La vista de alto nivel del nuevo flujo de trabajo será:

  1. Solicitud de anotaciones # voto (POST)
  2. filtro required_user falla
  3. render nueva sesión
  4. presentar información de inicio de sesión y original Los datos POST vuelven a las anotaciones # vote (POST)
  5. nuevo filtro en la información de las capturas de los votos de la sesión y se registra en. La votación procede como se esperaba. Si inicio de sesión falla volver a 3.
  6. anotaciones # voto redirecciones/rinde como debe

Empiece por volver a trabajar la require_user para hacer que los user_sessions # nueva plantilla.

def require_user 
    unless current_user 
    flash[:notice] = "You'll need to login or register to do that" 
    @user_session ||= UserSession.new 
    respond_to do |format| 
     format.html {render :template => 'user_sessions/new'} 
     format.js { 
     render :template => 'user_sessions/new', :layout => false 
     } 
    end 
    end 
end 

El @user_session ||= UserSession.new asegura que podemos volver a los errores de validación del formulario.

Ahora tenemos que reforzar su user_session # nueva plantilla para que pueda recordar la acción. Además, si planea usar lightboxes, esto debería ser un renderizado parcial representado por RJS relevante o new.html.erb.

Primero creamos un parcial para crear campos ocultos preservar los datos POST que se habrían perdido en una redirección:

<% if params[:controller] == "annotations" %> 
    <% content_for :old_form do %> 
    <%= hidden_field_tag "annotation[song_id]", params[:annotation][:song_id] %> 
    <%= hidden_field_tag "annotation[vote]", params[:annotation][:vote] %> 
    <% end %> 
<% end %> 

Luego de un procesamiento que parcial en el inicio de sesión parcial que ocupará su caja de luz:

<%= render :partial => vote_form_replica %> 

<% url = params[:controller] == "user_sessions ? user_sessions_url : {} %> 
<% form_tag @user_session, :url => url do |f| %> 
    <%= yield :old_form %> 
    <%= f.label :user_name %> 
    <%= f.text_field :user_name %> 
    <%= f.label :password %> 
    <%= f.password_field :password %> 
    <%= submit_tag %> 
<%end%> 

El hash vacío para url en form_tag parece un error, pero no lo es. Asegura que los datos del formulario se publiquen en la url que generó el formulario. Que en este punto deberían ser anotaciones /: id/vote

Ahora para el nuevo filtro para iniciar sesión. Básicamente, hará lo que haga UserSessionsController # create sin el render/redirect. Lo siguiente se copia del complemento de autenticación RESTful.

def authenticate 
    self.current_user = User.authenticate(params[:login], params[:password]) 
    if logged_in? 
    if params[:remember_me] == "1" 
     current_user.remember_me unless current_user.remember_token? 
     cookies[:auth_token] = { :value => self.current_user.remember_token, 
     :expires => self.current_user.remember_token_expires_at } 
    end 
    end 
end 

Lo único que queda es asegurarse de que el orden de los filtros sea correcto.

before_filter :authenticate, :require_user, :only => :vote 

N.B .: usted probablemente no va a utilizar esta versión de require_user sin esta versión de autenticar así que tiene sentido para combinarlos en un solo filtro.

Y eso es todo. La forma en que esto se ha configurado permite un código robusto DRY fácilmente reutilizable. Al colocar los nuevos filtros en ApplicationController están disponibles en cualquier controlador.A partir de este punto, agregar esta funcionalidad a cualquier otro controlador/acción requiere solo 3 simples pasos:

  1. Crear un nuevo modelo parcial después del voto_formulario parcial.
  2. Agregue la instrucción de representación correspondiente a la nueva plantilla de sesión.
  3. Aplica los filtros a tus acciones.
+0

Creo que tiene que combinar el ': authenticate' y': require_user' antes de los filtros. Como es, no puede llamar ': require_user' por separado porque el usuario nunca podrá iniciar sesión. Sin embargo, creo que este es el enfoque correcto en general, en particular, el truco' content_for' para "reproducir" el usuario acción deseada una vez que inicia sesión y la idea general de iniciar sesión en el usuario a través de un 'before_filter' es bastante inteligente –

+0

Gracias. el content_for no es realmente necesario, simplemente sentí que hacía que el código fuera más fácil de leer. Funciona mejor en tus parciales, por lo que adaptar esto para otros controladores/acciones requiere un nuevo render parcial y correspondiente: declaración parcial. He actualizado la solución para reflejar eso. Combinar los filtros authenticate y require_user en un único filtro es más práctico. Sentí que la explicación de la solución fluía mejor al dividirla en pasos atómicos que puede tomar para adaptar su código actual a este esquema. – EmFi

+0

Ah, también - no debería 'render: action => 'user_sessions/new'' be' render: template =>' user_sessions/new'' (en 'require_user')? –

0

Me gustaría acercarme a esto en la forma en que describes en la parte inferior de tu pregunta. Antes de mostrar la página inicialmente, verifique si el usuario está conectado. Si lo están, los enlaces "Me gusta" deben usar su comportamiento normal. Si no, enlace un evento de clic para mostrar el panel de registro/inicio de sesión. No hay nada sobre esto que no pueda ser reutilizado. De hecho, usamos este método exacto en mi trabajo. Cualquier acción del usuario que requiera autenticación sigue su comportamiento normal o muestra un panel de inicio de sesión genérico según el estado de inicio de sesión en el momento en que se carga la página.

+0

"Si no, enlace un evento de clic para mostrar el panel de registro/inicio de sesión" - Simplemente no quiero tener que hacer esto para cada acción que requiera que los usuarios inicien sesión (también, cuando el usuario ¿INICIE SESIÓN, cómo me aseguro de que se lleve a cabo cualquier acción que originalmente solicitó?) –

Cuestiones relacionadas