I have one running rails app with device gem. I want pass some urls with params (in url) in email. when user click on it and if user is logged in everything works (ULR is like myhost.com/myaction?my_var=xx)
but if user is not logged in it redirects to sign in path. after giving credentials it lost my_var value and app breaks. (yes it goes to my action)
for now I am redirecting user to his dashboard with error msg but anyone have good solution?
You are able to overwrite the default Devise behavior after a successful authentication by defining the after_sign_in_path_for method in your ApplicationController:
def after_sign_in_path_for(resource)
session[:stored_path] || stored_location_for(resource) || root_path
end
In this example Devise will check whether the session[:stored_path] is set, if not it will try to load the stored_location_for(resource) path and as a fail save it will eventually redirect_to the root_path.
In this case you'll need to set the session[:stored_path] upon redirect when the current_user isn't logged in.
Related
I have an app that is using Devise, I would like that after a user signs up, they are directed to a specific page, this page calls an API and saves the value from the API, I need this page to only be accessible or available after a user completes the sign-up form and clicks submit, and is then redirected to this page.
I do not want this page or URL accessible any other way but after sign-up, as the API will send a new value if accessed again. How can I accomplish this?
Once a user signs up they will be redirected to the page calling the API:
def after_sign_up_path_for(resource)
api_call_path ##path that can only be accessed after sign_up
end
The API is called and the response from the JSON data is automatically saved to the database once the page is opened, if the page gets opened again a new JSON response will be received with new data, which is what I would like to avoid.
So in a nutshell, my question is how can I restrict access to a specific path, and only make that path accessible if a user completes the sign-up form (devise) OR is there a way that I can run the code from the controller using a callback/filter after the user is created through the User model?
I was just busy with something similar. You do not need to direct the user to a page to run the code, you can just run the code that needs to be run after the user logs in the first time.
You need to create a Session Controller, and create a conditional statement that checks if the user has logged in previously:
#config/routes.rb
devise_for :users, controllers: { sessions: "sessions" }
#app/controllers/sessions_controller.rb
class SessionsController < Devise::SessionsController
def after_sign_in_path_for(resource)
if resource.sign_in_count == 1
##Do something awesome
else
root_path
end
end
end
As Emmanuel advised you can check futher info on the Devise Controllers.
Let's call the moment between after sign_up and showing the specific page - state A. So in the specific page controller you need to know - is the user in state A. You can achieve it by
1) saving to db (server side) that user is in state A after sign up and resetting state after showing specific page (you can do resetting triggered by client side to guarantee that page is showed).
2) saving to cookies (client side) after sign up then do as above.
Second solution is more clean in my opinion, but I do not know how strict is the rule to show only once
You can customize devise users controller by issuing
rails generate devise:controllers [scope]
Then customise UsersController such that after user is saved you can call your api code there
eg
def create
#user = ....
if #user.save
#user.call_api_method()
else
......
end
end
For more information check Configuring controllers
So, a returning user in my app who has ticked "Remember me" has to land in a different page inside the app instrad of the home page and being logged in there.
I went through the documentation but i cant find a function that does this.
I also struggle into make devise go to a different page when the user updates the profile and i use wrong methods for this. Can you give me the correct method and where to put it as well?
I tried using the method 'after_remembered' in my ApplicationController but it doesn't work while the method after_sign_in_path_for works!
Do i need to overwrite something?
Devise sets a remember_created_at value for the user if "Remember Me?" is selected. In the after_sign_in_path_for you could have it check for resource.remember_created_at and then perform the redirect there.
A quick example would be in app/controllers/application_controller.rb
def after_sign_in_path_for(resource)
resource.remember_created_at ? path_for_remember : path_not_for_remember
end
To handle redirects after updates you want to use the after_update_path_for which is set up the same way:
def after_update_path_for(resource)
some_path
end
I read the few posts about troubleshooting stored_location_for here, but can't seem to figure it out and not sure how to troubleshoot.
I tried deleting my custom after_sign_in_path_for, but that didn't work either. My location is never getting saved, although as I understand it after each session/page update it should store the location. Do I need to through that in as a filter manually?
def after_sign_in_path_for(resource)
stored_location_for(resource) ||
if resource.is_a?(Account)
add_quote_to_account(resource)
if resource.applications.any?
edit_application_path(resource.applications(true).last)
else
root_path
end
else
super
end
end
May be you are not storing the location where you want to redirect_to after signing in with devise. Devise provides two methods - store_location_for and stored_location_for
https://github.com/plataformatec/devise/blob/master/lib/devise/controllers/store_location.rb
Suppose your user model is named "user" then
A call to store_location_for(:user, my_desired_path) in your controller will store the url "my_desired_path" in session with key "user_return_to". Basically this method will simply do this - session["user_return_to"] = my_desired_path. Probably you are missing this. I have a booking controller and a "login" action which stores the checkout location for booking in booking controller and then displays a login form for users in rendered view -
def login
my_desired_path = url_for(controller: 'bookings', action: 'checkout')
store_location_for(:user, my_desired_path)
end
Now you can use stored_location_for(:user) to retrieve my_desired_path from your session. So to say, a call to stored_location_for(:user) will return "my_desired_path.
Now if you use stored_location_for in your custom after_sign_in_path_for(:user) then it shall return "my_desired_path".
Additional Point -
A call to stored_location_for(:user) returns session[:user_return_to] but also clears this session after returning the value if your redirect format is navigational format. So a second call to stored_location_for(:user) will not return my_desired_path. And sometimes this is how we want our application to behave. On contrary, if your redirect format is not navigational format then session wont be cleared and a second sign-in will again redirect to same "my_desired_path".
Sometimes you want to redirect to different locations in signing-in from different pages in your application. Suppose, you want to redirect to "\X" on page A and to "\Y" on page B. Now follow these steps -
User in on page A - store_location_for(:user, "\X") is saved in session.
Application provides a sign-in form but User does not sign-in and just browse here and there in your application.
User is on page B and perform a sign-in expecting to land on "\Y" but unexpectedly lands to "\X".
So take care of it in your application. This scenario is more likely to occur in applications which uses AJAX for signing-in.
I am using Rails 3 and Devise for authentication.
I want to track whenever a user enters my site from another domain or by typing in the URL. Assume the following page on my site:
http://www.mysite.com/somepage
If a visitor requests this URL by clicking a link on another site or types it in to his browser, I want to put the URL into a cookie for later use. If /somepage does not require login it works fine. In a before_filter I just check to see if the referrer is not from mysite.com.
However, when /somepage requires a login, Devise makes a redirect, which results in a second request to my login page. The original referrer is carried forward to the new request. So my code thinks it's the original requested URL and overwrites the cookie. Wrong.
I'm probably just having a mental block, but I can't see how to determine that the page that is redirected to is not original page requested.
You could probably get some ideas from this article.
It seems like you should filter out anything that includes the user path, since you have no problem getting the referrer if the page doesn't require login.
So for example you could use a regex to filter out users/sign_in, users/sign_out, etc.
request.referrer = request.fullpath unless request.fullpath =~ /\/users/
or
request.env['HTTP_REFERER'] = request.fullpath unless request.fullpath =~ /\/users/
You would need to put this in some kind of before_filter above the authenticate before_filter so it is called first.
I'm wondering if I'm asking too much of Devise. I'd like to allow a visitor to fill out a form and then but then be required to sign up when they press the "submit" button. That's the easy part. My problem is that once the user is redirected to the sign up form and they fill it out, I can't get them redirected back to the original form so that that form can be submitted (but now with the user ID).
I've played around with the "after_sign_in_path_for(resource)" method in the application controller, but my problem is that after signup, the request.referer isn't the original form, it's the signup form. I thought about using a before_filter :store_location callback, but then I realized that it'll store the most recent location, which is the url for the signup form.
How do I set up devise that original form as the correct location to render after sign up?
P.S. This question comes from a related one, located here.
Try this make 2 method in ApplicationController which saves
the current url to the session, and another that redirects to the stored
url (which should have a default in case it can't find it). Then, in
pages which i want to bookmark for returning to (you might not want
someone to get sent back to some pages), then save the url.
EG in application.rb
def store_location
session['saved_location'] = request.request_uri
end
def redirect_to_back_or_default(default)
if session['saved_location'].nil?
redirect_to default
else
redirect_to session['return-to']
session['saved_location'] = nil
end
end
Then, in a page that you want the user to be able to go back to:
Then, just call
redirect_to_back_or_default('enter your chosen default url here, depending on context')
in after_sign_in_path_for(resource_or_scope) to send someone back.