I've followed the tutorial on the following article for how to deactivate users:
https://github.com/plataformatec/devise/wiki/How-to:-Soft-delete-a-user-when-user-deletes-account
My question is, how do I make it so that when a deactivated user signs in, it shows them a page that allows the to reactivate their account? IE: "users/reactivate" with a button to reactivate?
I know I have to rewrite the default Users sessions controller of course, but I'm not quite sure at what point or how active_for_authentication is called, and how I can overwrite the redirect.
When a user attempts to log in, the request is routed to the create method of your sessions_controller.rb, where a session for this user is created if credentials are valid. Within that method, you just need to check whether the deleted_atcolumn is populated, followed by some branching logic to either redirect to whatever landing page you have for valid logins or your reactivation page.
Your code would look something like the following sample, but again, you didn't provide implementation details, so it falls to you to adapt:
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
unless user.deleted_at.nil?
my_user_login_method
redirect_to user # or redirect to a dashboard/landing page/whatever
else
render 'reactivate' # this would be a view for your reactivation page
end
else
flash.now[:danger] = 'Invalid email/password combination'
render 'new'
end
end
Related
I am using devise for user registrations. I set up a custom edit page '/info' to use as an additional signup page. The only problem is after you submit the edits on the info page it redirects to the user profile. I am able to change it redirect to the home page (where I want after /info) but then it also redirects there from the normal edit page. I am not sure how to redirect based on what page the user is on.
My one idea was to get the users current path and use an if statement but I haven't been able to get that to work.
registrations_controller.rb:
def update
...
current_uri = request.env['PATH_INFO']
if current_uri == '/info'
redirect_to root_path, notice: "Welcome"
else
redirect_to user_path(#user)
end
end
Normally it just looks like this:
def update
...
redirect_to user_path(#user)
end
The problem seems to be you need to keep data around to determine where to redirect. A few ideas:
You could store data in the session when a user visits a previous page and check this data in your action to determine where to redirect the user. The session is often a convenient place to store things that are consistent between requests but that should not be persisted to the database.
You could store data in the database (for instance, add a flag to your user model) and check this to determine where to redirect.
You could check request.referer and redirect based on the value there. This may not be as reliable.
In my application I am trying to enforce that users be signed in to preform certain actions. And when they try to preform these actions when not signed, they are redirected to the 'Sign-In' page, and once they have signed in, they are redirected back to the page they were trying to access. I have all of this working properly with the below code.
Controllers Code
if !(signed_in?)
session[:return_to] = newcompany_path
redirect_to signin_path
flash[:notice] = "You must be signed in to add companies."
else
#company = Company.new
#primary_field = ##fields
end
...
redirect_path = session[:return_to]
if user && user.authenticate(params[:session][:password])
sign_in user
session[:return_to] = nil
if (redirect_path == nil)
redirect_to user
else
redirect_to redirect_path
end
else
The issue I am running into is, if the user clicks away from the sign-in page without actually signing in, the session[return_to] variable is not cleared properly, and if they then go back to sign in later, they are redirected to the wrong page.
So, how would I set it up so if the user clicks away from the sign-in page, the session[:redirect_to] variable is reset?
You could pass the return_to path in query string parameter rather than the session and submit it alongside the sign in form so that it only applies for that form, rather than subsequent requests.
When redirecting to the sign in form, it'd look like:
redirect_to signin_path(return_to: newcompany_path)
Then, in your sign in form, make sure to include a hidden field with the return_to value, like:
hidden_field_tag :return_to, params[:return_to]
Then in your controller action for signing in, you'll check params[:return_to] rather than session[:return_to] to get the path you want.
Is this what you're looking for?
redirect_to request.referrer
I have implemented redirect_to_back method in my ApplicationController for users that are not signed in (from this blogpost:
def redirect_to_back_or_default(default = root_url)
if request.env["HTTP_REFERER"].present? and request.env["HTTP_REFERER"] != request.env["REQUEST_URI"]
redirect_to :back
else
redirect_to dashboard_url
end
end
and I'm using in sessions_controller#create:
if #user && #user.authenticate(params[:password])
sign_in(#user)
redirect_to_back_or_default(dashboard_url)
else
...
The problem is, this only works if the request is coming from the application and not if it is a direct link, like in an email.
Is there a solution for this?
I would recommend altering how you accomplish this. If you follow the flow below I think it will produce the results you're looking for:
User arrives at URL (either by clicking link in email or typing it or whatever) but is not yet authenticated.
Store the URL that the user is at in the session
Redirect to the sign-in controller/action
After authenticating the user look in the session for where you stored the arrival URL
If present redirect to that URL (and clear stored URL out of the session) otherwise redirect to dashboard_url (it won't be present if someone navigates directly to the sign-in controller/action).
I am using Omniauth to make users sign up with Facebook account. When they first click on the auth link, I direct them to the sign up page for them to put some additional information, unless they already have an account for my application.
SessionsController
def create_facebook
#make an environment variable
auth = request.env['omniauth.auth']
if User.find_by_provider_and_uid(auth["provider"], auth["uid"])
user = User.find_by_provider_and_uid(auth["provider"], auth["uid"])
session[:user_id] = user.id
redirect_to lessons_path, flash[:notice] => "Signed in!"
else
#go to signup page to get additional info
redirect_to new_user_path(:auth => auth) #problem
end
end
In this case, I'm passing the entire auth hash using a parameter in the URL because I want to call User.create_with_omniauth(auth) in Users#new. Should I avoid from doing it? What are the other alternatives?
You've got a few approaches that I can see:
Store the auth value in the user's session (but bear in mind that the session doesn't encrypt values by default; it only signs them), and then pull them out when viewing the new user action.
Alternatively:
Just call the new user action code directly (either share it via a helper, or if it's on the same controller - call the action and then make sure you call render to set up the correct view)
A third and more robust alternative that is similar to the session approach, but a little more heavyweight:
Set up the user with what information you have at this step (and set them to some sort of "partially registered" state). Sign them in. Then make sure you read in any existing data when viewing the new_user action. Might also want to set up your routing layer to always redirect users in this state to the sign up page no matter where they are.
Here is what I have for redirecting to a default url(myapp_url). But I want to change redirect to go the request url was entered by the user after authentication.
How do I do that? I tried couple of options from searching here, like :back. But no go.
User enters an url, if not authenticated then gets redirected to the login page, then after login user shall be redirected to the original request url.
def create
user = User.Authenticate(params[:user_id], params[:password])
if user
session[:user_id] = user.id
redirect_to myapp_url, :notice => "Logged in!"
else
flash.now.alert = "Invalid email or password"
render "new"
end
end
You can read the chapter about "Friendly forwarding" in the "Ruby on Rails Tutorial" by Michael Hartl to see how you can easily implement it.
Basically you have 3 helper methods:
store_location to store the user desired location in the session
redirect_back_or(url) redirect the user to the location stored in the session or, if not set, to the location contained in the url method param
and clear_return_to used "internally" by the redirect_back_or method to clear this piece of information once used
And then you use these methods:
A) when you see a guest user try to access a page that needs authentication use store_location before redirect him to the login page.
B) when a user is logged in, you use redirect_back_or(url) to redirect him to the right location (if present of course)
This is an overview of how this work, you get the idea but I suggest to read that chapter for the implementation (few) details.
You need to save path in session before redirection on authentication, and after successful auth redirect to this path.