ruby on rails 3 - rails - Devise-Redirigir la página después de la confirmación
install devise rails 5 (3)
Digamos que un usuario hace clic en un enlace a una página que está protegida. Luego se redirigen a una pantalla de inicio de sesión donde pueden iniciar sesión. Si lo hacen, se redirigen con éxito a esa página. Pero si no tienen una cuenta tienen que registrarse. Aquí es donde las cosas se complican porque estoy haciendo una confirmación por correo electrónico.
Al hacer clic en un enlace, se crea una nueva sesión si no puedo redirigir automáticamente al usuario a esa página protegida. Estoy intentando cambiar esto poniendo una referencia a la redirección dentro del enlace de confirmación. Me gustaría hacer:
<%= link_to ''Confirm my account'', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token, :redirect_to => stored_location_for(@resource)) %>
Pero no puedo averiguar cómo obtener acceso a stored_location_for
(o si esa es incluso la ubicación correcta para obtener). Se define en Devise::Controllers::Helpers
, pero es un método de instancia, por lo que no puedo hacer Devise::Controllers::Helpers.stored_location_for(…)
.
Mi pregunta es ¿cómo obtengo acceso a stored_location_for
O O cuál es la mejor manera de hacer esto?
Mi objetivo es hacer eso y luego en mi ConfirmationsController personalizado definir:
def show
if params[:redirect_to]
session["user_return_to"] = params[:redirect_to]
end
super
end
Eso debería funcionar bien?
En cuanto a la forma de storage_location_for se ha implementado en lib / devise / controllers / helpers.rb
def stored_location_for(resource_or_scope)
scope = Devise::Mapping.find_scope!(resource_or_scope)
session.delete("#{scope}_return_to")
end
De lo contrario, es posible acceder a él mediante la sesión [''user_return_to'']. En su caso, perdería ese objeto de sesión porque cuando el usuario hace clic en el enlace del correo de confirmación, puede ser una sesión nueva que se genera.
Puede implementar lo que haya sugerido como un filtro anterior:
class Users::ConfirmationsController < Devise::ConfirmationsController
before_filter :set_redirect_location, :only => :show
def set_redirect_location
session["user_return_to"] = params[:redirect_to] if params[:redirect_to]
end
end
Además de esto, tendrá que modificar la ruta para hacer que el dispositivo llame a su controlador en lugar de su propio controlador de confirmación.
devise_for :users,
:controllers => { :confirmations => ''users/confirmations''}
Espero que esto ayude :)
Nota: los fragmentos de código no están completos y solo contienen detalles relevantes.
Ok, finalmente lo descubrí. No estoy seguro de si esto cambia en absoluto con la actualización que hizo Devise ayer al hacer que Devise :: Mailer pusiera la mayor parte de su funcionalidad en un módulo (vea el código here y el ticket here ).
Básicamente, se reduce a no poder acceder a la session
dentro de una vista de correo. Por lo tanto tienes que pasar la redirección como variable. Devise utiliza un método after_create
en su recurso ( User
en mi caso) que luego envía el correo electrónico de confirmación. Esto significaba que no podía pasar la variable de sesión directamente al remitente. Por lo tanto, siento que este es un trabajo bastante desagradable para obtener esta funcionalidad. Pero aquí está el código.
Entonces, para obtener la variable redirect_to en la aplicación de correo, debe agregar una variable al usuario. Así:
class User < ActiveRecord::Base
…
attr_accessor :return_to
…
end
Luego tienes que establecer esa variable cuando creas al usuario por primera vez. Ya tenía una configuración de controlador personalizada para el registro (vea el tema sobre cómo configurar esto, o vea la respuesta de @ ramc para obtener instrucciones). Pero fue relativamente fácil hacer esta parte, simplemente la agregué a los parámetros y dejé que el resto se encargara de sí mismo.
class RegistrationsController < Devise::RegistrationsController
def create
params[:user][:return_to] = session[:user_return_to] if session[:user_return_to]
…
super
end
end
Ahora el usuario tiene una variable return_to
que se establece. Solo necesitamos acceder a eso en el correo electrónico confirmación_instrucciones. Ya he reescrito parte de confirmation_instructions.html.erb, por lo que en ese momento acabo de agregar:
<% if @resource.return_to %>
<%= link_to ''Confirm my account'', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token, :redirect_to => @resource.return_to) %>
<% else %>
<%= link_to ''Confirm my account'', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %>
<% end %>
(para aquellos que son nuevos en esto, @resource es la variable que Devise usa para definir a su usuario).
Ahora, una vez que el usuario haga clic en ese enlace, debemos redirigirlos. El filtro de @ ramc''s funciona bien para esto.
class ConfirmationsController < Devise::ConfirmationsController
before_filter :set_redirect_location, :only => :show
def set_redirect_location
session[:user_return_to] = params[:redirect_to] if params[:redirect_to]
end
end
Eso se hará cargo del caso en el que un nuevo usuario vaya a una página protegida, luego se registre, haga clic en el enlace de confirmación y se redireccione correctamente a la página protegida.
Ahora solo tenemos que ocuparnos del caso en el que un usuario hace lo anterior, pero en lugar de hacer clic en el enlace, intentan volver a la página protegida. En este caso, se les solicita que se registren / inicien sesión. Se registran y luego se les pide que confirmen su correo electrónico y se les da la opción de reenviar el correo electrónico de confirmación. Pusieron su correo electrónico y ahora necesitamos poner la variable redirect_to en ese nuevo correo electrónico de confirmación.
Para hacer esto necesitamos modificar el ConfirmationController, de manera similar a como lo hicimos con el RegistrationController. Esta vez necesitamos modificar el método de creación. La forma de trabajar fuera de la caja es llamar a un método de clase en el usuario llamado send_confirmation_instructions
. Queremos reescribir ese método para que podamos pasarle la variable return_to
.
class ConfirmationsController < Devise::ConfirmationsController
def create
self.resource = resource_class.send_confirmation_instructions(params[resource_name],session[:user_return_to])
if resource.errors.empty?
set_flash_message(:notice, :send_instructions) if is_navigational_format?
respond_with resource, :location => after_resending_confirmation_instructions_path_for(resource_name)
else
respond_with_navigational(resource){ render_with_scope :new }
end
end
end
Lo único diferente a lo que viene con el dispositivo es la primera línea de creación. Pasamos dos variables. Ahora necesitamos reescribir ese método.
class User < ActiveRecord::Base
def self.send_confirmation_instructions(attributes={},redirect=nil)
confirmable = find_or_initialize_with_errors(confirmation_keys, attributes, :not_found)
confirmable.return_to = redirect if confirmable.persisted?
confirmable.resend_confirmation_token if confirmable.persisted?
confirmable
end
end
confirmable
convierte en una instancia de usuario (el usuario actual se basa en el correo electrónico). Así que solo necesitamos establecer return_to
.
Eso es.
Por lo que puedo ver en los comentarios en el código fuente del dispositivo, todo lo que necesita hacer es implementar lo siguiente en su registrations_controller.rb:
def after_inactive_sign_up_path_for(resource_or_scope)
session["user_return_to"]
end