-
Notifications
You must be signed in to change notification settings - Fork 0
How To: Create a guest user
In some applications, it's useful to have a guest User
object to pass around even before the (human) user has registered or logged in. Normally, you want this guest user to persist as long as the browser session persists.
Our approach is to create a guest user object in the database and store its id in session[:guest_user_id]
. When (and if) the user registers or logs in, we delete the guest user and clear the session variable. A helper function, current_or_guest_user
, returns guest_user
if the user is not logged in and current_user
if the user is logged in.
# file: app/helpers/application_helper.rb
module ApplicationHelper
...
# if user is logged in, return current_user, else return guest_user
def current_or_guest_user
if current_user
if session[:guest_user_id]
logging_in
guest_user.destroy
session[:guest_user_id] = nil
end
current_user
else
guest_user
end
end
# find guest_user object associated with the current session,
# creating one as needed
def guest_user
guest_user_id = session[:guest_user_id] ||= User.create(:name => "guest").id
User.find(guest_user_id)
end
# called (once) when the user logs in, insert any code your application needs
# to hand off from guest_user to current_user.
def logging_in
end
...
end
The above approach did not work for me in Rails 3.0.9 - I'm not sure if it's because I did something wrong or if the above was for a different version of Rails. When I tried to apply the above solution I found 3 problems:
- When I put the code in the application_helper my controller where I was using the code could not find any of the methods
- When I moved it to application_controller it started to work except the User was not being created in the database
- When I tried to use it with an ajax request it created a new user on each request instead of using the one stored in guest_session_id
So here is my working solution:
# file: app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
# if user is logged in, return current_user, else return guest_user
def current_or_guest_user
if current_user
if session[:guest_user_id]
logging_in
guest_user.destroy
session[:guest_user_id] = nil
end
current_user
else
guest_user
end
end
# find guest_user object associated with the current session,
# creating one as needed
def guest_user
User.find(session[:guest_user_id].nil? ? session[:guest_user_id] = create_guest_user.id : session[:guest_user_id])
end
# called (once) when the user logs in, insert any code your application needs
# to hand off from guest_user to current_user.
def logging_in
end
private
def create_guest_user
u = User.create(:name => "guest", :email => "guest_#{Time.now.to_i}#{rand(99)}@email_address.com")
u.save(false)
u
end
end
Finally in order to fix the problem with ajax requests you have to turn off protect_from_forgery for the controller action with the ajax request:
skip_before_filter :verify_authenticity_token, :only => [:name_of_your_action]
Another option is to remove protect_from_forgery from application_controller.rb and put in each of your controllers and use :except on the ajax ones:
protect_from_forgery :except => :receive_guess