I'm using Devise for user authentication in a rails application, and so certain routes are wrapped in a authenticate tag to allow access only to users who are logged in.
authenticate :user do
post '/user/orders/new', to: 'user/orders#new', as: :new_user_order
end
For example, when a user tries to create a new order when they're not logged in, they're redirected to a sign in page.
What I want is for the user to be directed to the new order page after logging in.
Currently, we're using request.referrer which redirects the user back to the page they were on before trying to create a new order. I can't seem to figure out a way of getting the path they were targeting before being sent to sign in.
Anybody know how I could do this?
Thanks
You need to provide a before filter for user authentication in the controller and not mention it in routes . Just put the following code in the controller and it should redirect to sign-up if the user isn't logged in -
before_filter :authenticate_user
You need to override Devise's after_sign_in_path_for(resource_or_scope) method, you can do it in application controller
def after_sign_in_path_for(resource_or_scope)
# new_order_path
end
Hope that helped!
You can persist the last url - in session[:bookmark] and by doing something like this -
prepend_before_filter :set_bookmark
def set_bookmark
session[:bookmark] = request.url
end
And within SessionsController, you can use value of session[:bookmark] if it exists or after_sign_in_path_for
Related
I am using devise and want to redirect users to a confirmation page upon signup, this is what I am doing right now:
users/registrations_controller.html.erb
class Users::RegistrationsController < Devise::RegistrationsController
def confirm_email
end
private
def after_inactive_sign_up_path_for(resource)
users_confirmyouremail_path
end
end
config/routes.rb
devise_scope :user do
get 'users/confirmyouremail' => 'users/registrations#confirm_email'
end
I have no problem with redirecting the page after signup. However, I think it is quite weird that anyone can visit the page with url like `host.com/confirmyouremail' and see the confirmation page. Are there any ways I can write a route that will use random code that is allow only for one time visit? Thanks in advance.
Maybe something like this:
before_action :authenticate_user!
def confirm_mail
redirect_to root_path if current_user.confirmed
...
end
You are storing in the database if the user has already confirmed his account. If his account is confirmed then he won't be able to access this page. You can redirect to whatever page you want. A user without any account won't be able to access this page because of the before action
In case the user is not logged in when he accesses this confirm_mail page you have different possibilities. You could use a session or a cookie:
# after sign up:
session[:confirm] = true
# alternatively a cookie
cookies[:confirm] = true
Then in the confirm mail action:
def confirm_mail
if session[:confirm].blank? # or cookies[:confirm].blank?
redirect_to root_path
end
# otherwise delete the field from the session
session.delete(:confirm)
# alternatively the cookie
cookies.delete(:confirm)
end
Another way would be by using a Token. You create a new model like ConfirmMailToken. Then on sign up you create a new token and redirect the user to the confirm page with the token as a URL param. Then in the confirm_mail action you check if a token is available and delete it if it is. This way you ensure that the page is only shown after redirect.
If unauthenticated users attempt to access users/edit , devise redirects them to users/sign_in. This is good. However, after successful signing in, I wish the user to be redirected back to users/edit. How is this possible.
Have you overriden the after_sign_in_path_for method? Check out the wiki about How To: redirect to a specific page on successful sign in
Anyway, AFAIK, if you haven't overriden this method, the default behaviour is redirect user to the last stored location, 'users/edit' in that case. Check out the content of stored_location_for on your application before user is signed in.
I interpret the question as how do I redirect back after sign in, where the answer would be thus:
https://github.com/plataformatec/devise/wiki/How-To:-redirect-to-a-specific-page-on-successful-sign-in
class ApplicationController < ActionController::Base
def after_sign_in_path_for(resource)
request.env['omniauth.origin'] || stored_location_for(resource) || root_path
end
end
I use Devise gem. It's not configured to be :confirmable, however I want an user not to log in automatically right after a registration process. For some reason, now they are logged in automatically which exactly the opposite of what I want.
So how do I do that?
https://github.com/plataformatec/devise/wiki/How-To:-Redirect-to-a-specific-page-on-successful-sign-up-(registration)
Basically, follow the above steps. In your after_sign_up_path_for method, you can call
sign_out resource
then redirect them to whatever page you want them to go to (perhaps root, or the login page).
The user is logged in via the sign_up method called by devise; it's standard procedure -- many websites log in users immediately after they sign up. Most that don't require confirmation first, so your use case it somewhat atypical. Still, doing the method I described above should do what you want, without having to implement confirmable or doing any membership approvals.
Signing in the user after sign up is achieved by the sign_up method in Devise::RegistrationsController that gets called by the [create][1] action. You can simply override this method with an empty one to prevent signing in. That worked for me!
In app/controllers/users/registrations_controller.rb:
class Users::RegistrationsController < Devise::RegistrationsController
def sign_up(resource_name, resource)
end
end
Note: replace users with your table name.
Extra:
If you allow only admins to add new users , or perhaps other admins, and use the create action to add them, this previous method will also give you the benefit of not having to sign out. You can customize what page to be redirected to after signup by overriding the after_sign_up_path_for method in app/controllers/application_controller.rb:
class ApplicationController < ActionController::Base
def after_sign_up_path_for(user)
'/users/show' # replace with the path you want
end
How do I redirect a user to a specific page when they login on a particular form I create with Devise? There's this howto page for Devise on how to redirect to a particular page after sign in. However, I want different forms to sign in to different target pages. Ideally, I can just add another HTML form parameter like this:
<input type="hidden" name="target" value="/dashboard"/>
UPDATE: It's important that I maintain the normal functionality of Devise for a login page. That is, if I click on a link that has a before_filter :authenticate_user! in its controller, then I'll be redirected to a login page. After logging in, then I'm redirected to the original destination page.
Actually you can simply define the after_sign_in_path_for method in your controller like that :
class ApplicationController < ActionController::Base
def after_sign_in_path_for
params[:target] || some_default_url
end
end
And then if your different sign in forms have different targets, then user should be properly redirected
Adding
<input type="hidden" name="target" value="/dashboard"/>
to each particular form that would redirect to a specific page will then be enough :)
EDIT : I think I finally understood what you exactly want. So here what I would do (based on this blogpost)
class ApplicationController < ActionController::Base
protect_from_forgery
def after_sign_in_path_for(user)
origin_path = session[:origin_path]
clear_origin_path
if origin_path.present?
origin_path
else
params[:target].presence || default_redirect_path
end
end
private
def authenticate_user!
store_origin_path
super
end
def store_origin_path
session[:origin_path] = request.fullpath
end
def clear_origin_path
session[:origin_path] = nil
end
end
So basically, if you try to access a protected path (let's say /protected_resource), the path will be stored in the session, and then once user is logged in, the session will be cleared and user correctly redirected
Then if a user goes on one of your different sign_in form and if that form contains a target input, then user will be redirected to that target.
Finally, if user goes on a form without any target he'll be redirected to a default_redirect_path that you might want to customize.
Last thing : I assumed that the redirection to the original request was more important than the target so let's say a user goes on /protected_resource and is therefore redirected to a sign_in form, even though this sign_in form has a target input, user will be redirected to /protected_resource after a successful sign in.
You can easily change that by inverting the conditions in the after_sign_in_path_for method
There might be a better way to do that, but this a starting point for you, and you might want to improve it ;)
Let me know if my answer is not detailed enough.
I need a 'Contact' link for both authenticated and unauthenticated users that will send them to
new_user_widget_path(current_user)
This doesn't work for unauthenticated users of course because there is no current user. The method I've been using to solve this problem is to have two routes:
resources :widgets, only: :new
resources :users do
resources :widgets
end
The only purpose of the first route is to provide redirection in the unauthenticated case, and then redirect that user to the new widget page once he signs in.
class WidgetsController < ApplicationController
before_filter :authenticate_user!
def new
redirect_to new_user_widget_path(current_user)
end
end
This works perfectly well, but I'm curious, has anyone come across a more elegant solution to this problem?
I don't think there is anything particularly wrong with your approach. An alternative is to have a guest user. In my app, if a user requests a page with needs authentication, I redirect them to the login page, and then redirect them to the page they were trying to go once they log in. If you have a system like this, you can check if the guest id is in the full path and replace it with the now logged in current_user id.
User is not signed in and but you want proper redirection. In the view you can do this:
new_user_widget_path(current_user || "_")
And then add this to application_controller.rb
def stored_location_for(resource_or_scope)
if path = super
prefix = polymorphic_path(current_user.class)
path.gsub!("#{prefix}/_", "#{prefix}/#{current_user.id}")
end
end
which replaces the underscore with correct ID.
This is implemented on top of Devise's stored_location_for method but it can easily be adapted to other authentication setups.