Is there a way to hook into signin process (using devise), to merge "guest" session data before signing in, and some other data (Mysql) after signin in?
For example I need to merge user's cart data from session, when he goes to ordering step and logs in, and already has items in DB
Found some solutions here, but I don't want to create guest users in DB, just need to merge sessions
It would be a bit hacky, but you could do it in the after_sign_in_path_for controller method.
class ApplicationController
def after_sign_in_path_for(user)
merge_cart_from session[:cart] # or whatever
root_path
end
end
Related
I have rails app with:
Admin table with Devise authentication
User table with email and name without authentication (but session to remember them)
User can browse anywhere but now on certain pages I would like to enhance it and add authentication - allow user to create password and only with password it will be accessible but I am quite lost what is the best way to do it with the current setting?
I allow users to add their details like name and email and I am creating a cookie to remember them without any authentication or password:
UsersController
def create
user = User.find_or_create_by(email: params[:user][:email])
cookies.permanent.signed[:user_id] = user.id
session[:user_id] = user.id # for users/edit temporary
render json: user
end
Let's say I have this following method in User:
before_filter :authenticate_user!, only: :your_order
def your_order
end
If User will visit this page and didn't set up password before, how can I prompt him to create one and how can I require for him to login after with Devise? I am thinking of more solutions but none of them are perfect.
As per the specifications given the below mentioned criteria might help you.
def your_order #before_filter
if user.password.present?
# authenticate using valid_password? method of devise
else
#redirect user to say set_password
end
end
def set_password
#set the user password in this method and after successful completion redirect to login page where before filter your_order will be called
end
I'm working on google authentication for a rails app. Currently using the omniauth-google-oauth2 gem to implement Google auth. I've managed to have users sign in using google. However, I'd also like users to be able to sign up using google. My problem is that I've matched the google callback URL to a particular controller action (sessions#create).
Is it possible to choose between 2 redirect URIs based on whether users are signing in or signing up? Currently, my only idea is to create new google client credentials to be used for sign up, I hope there is a better way.
You don't need to have 2 redirect uris, you just need to do some more work when receiving the callback. For instance:
class SessionsController < ApplicationController
...
def create
email = auth_hash['info']['email'] # assuming your omniauth hash is auth_hash and you're requiring the email scope
#user = User.find_by(email: email) if !email.blank? # assuming your user model is User
if #user
login_user(#user) # use your login method
elsif !email.blank?
#user = User.new(name: auth_hash['info']['name'], email: email)
unless #user.save!(validate: false) # validate false because I'm enforcing passwords on devise - hence I need to allow passwordless register here)
# deal with error on saving
end
else
# deal with no found user and no email
end
end
protected
def auth_hash
request.env['omniauth.auth']
end
end
I've written all steps but the creation process can be shortened to:
#user = User.create_with(name: auth_hash['info']['name']).find_or_initialize_by(email: email)
#user.save! if #user.new_record?
if #user
login_user(#user)
else
# deal with no user
end
Nonetheless, you can't be sure the user is going to give you scope access to the email, so personally I think the first version, even if a bit lengthier is more robust. Then on the shorter version there's also the problem of, if #user is false, why is so? And will require you to add more logic to figure out why is that, whereas in the first one it's much easier to apply the correct response to each situation.
I have an app where users log in and the LDAP server is used to authenticate them. That part I have down, but the hiccup comes when dealing with the users and multiple sessions.
When a user is authenticated I create a new user object from a user model that inherits from ActiveModel, saves their name and email from the LDAP entry. This is done in sessions_controller with user as an instance variable. i.e. #user = User.new
However when current_user in application_controller checks for the user object, it's value is nil.
I'm guessing this is a scoping issue where the application controller can't see the instance variable in session controller's value.
Without using a database, how could I handle saving this minimal info about a user and have it persist through out their session? Before when using a class variable ##user and setting it in application_controller other users were only able to log in one at a time...Thanks for any help in advance!
Assuming your User object is small, you can store it in the session.
class SessionController < ApplicationController
def authenticate
# Handle LDAP-auth and we now have a user
# ldap_authenticated? should be true
# ldap_user contains relevant info from LDAP
session[:user] = User.new(email: ldap_user.email) if ldap_authenticated?
end
end
module ApplicationHelper
# Use this to access the current user everywhere in the app
def current_user
session[:user]
end
end
How can I sign a user out without their session (i.e. they're not the current_user).
I've tried the sign_out(user) controller helper, but that seems to sign out the current_user regardless of the user it's passed.
I can't seem to find a relationship between the sessions table and the users table either.
I'd appreciate any help.
try sign_out #user
where #user is the user instance which admin wants to logout
I'm using Restful Authentication and I'd like to be able to log in as different users on our site to investigate issues they may be having ("see what they see"). Since all passwords are encrypted I obviously can't just use their passwords.
So, how can I force a session to be logged in as a specific user?
In your sessions_controller add action impersonate like this:
def impersonate
user = User.find(params[:id])
logout_killing_session!
self.current_user = user
flash[:notice] = t(:logged_in)
redirect_to root_url
end
Then in your routes extend session resource with the member impersonate:
map.resource :session, :member => {:impersonate => :post}
Finally, somewhere in your admin views add a button to each user called "Impersonate". It will have to look something like this (assuming that user is in local variable user):
<%= button_to "Impersonate", impersonate_session_path(:id => user.id) %>
Using this approach you also avoid overriding any tracking data such as time of the last login, etc.
P.S. Don't forget to require admin for impersonate action in sessions controller.
Simply override session[:user_id] with the id of the user you want to be. One easy way is to have the user log in as an admin and then give them a drop-down of usernames. When they submit the form, have the controller set session[:user_id] and then reload current_user. The admin will then 'become' that user.