Aquí hay algunos problemas que superar.
Los navegadores en general no permiten el redireccionamiento a una solicitud POST.
redirect_to no conserva el formato sin entrada adicional.
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á:
- Solicitud de anotaciones # voto (POST)
- filtro required_user falla
- render nueva sesión
- presentar información de inicio de sesión y original Los datos POST vuelven a las anotaciones # vote (POST)
- 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.
- 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:
- Crear un nuevo modelo parcial después del voto_formulario parcial.
- Agregue la instrucción de representación correspondiente a la nueva plantilla de sesión.
- Aplica los filtros a tus acciones.
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 –
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
Ah, también - no debería 'render: action => 'user_sessions/new'' be' render: template =>' user_sessions/new'' (en 'require_user')? –