Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gradual engagement, persistent guest user with Devise

I'm trying to set up gradual engagement in my utility app which people can use without registering e.g. notepad.cc and jsfiddle.net and I plan to create a guest user (with Devise) for the user when he 'writes' to the app.

I found this guide on the Devise wiki https://github.com/plataformatec/devise/wiki/How-To:-Create-a-guest-user which shows how to create a guest user for the duration of the browser session. What I want is for the user to continue using the same guest account in subsequent visits, until he signs up, maybe when I introduce subscription plans for more features.

How can I modify what's in the guide to make this possible?

Code in the guide linked above:

# 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

And using it in the controller:

@thing.user = current_or_guest_user
@thing.save
like image 285
Aen Tan Avatar asked Nov 25 '11 09:11

Aen Tan


2 Answers

After some yak-shaving I've managed to get it to work. Here's the working code:

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 cookies[:uuid]
        logging_in # Look at this method to see how handing over works
        guest_user.destroy # Stuff have been handed over. Guest isn't needed anymore.
        cookies.delete :uuid # The cookie is also irrelevant now
      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_by_lazy_id(cookies[:uuid].nil? ? create_guest_user.lazy_id : cookies[:uuid])
  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
      # What should be done here is take all that belongs to user with lazy_id matching current_user's uuid cookie... then associate them with current_user
  end

  private

    def create_guest_user
        uuid = rand(36**64).to_s(36)
        temp_email = "guest_#{uuid}@email_address.com"
        u = User.create(:email => temp_email, :lazy_id => uuid)
        u.save(:validate => false)
        cookies[:uuid] = { :value => uuid, :path => '/', :expires => 5.years.from_now }
        u
      end

end

I will accept another answer if you can show me a better way to do this.

like image 77
Aen Tan Avatar answered Nov 17 '22 16:11

Aen Tan


The above solution works great.

Don't forget to setuphelper_method :current_or_guest_user to make the method accessible in views. Took me some time to figure out.

like image 4
mik Avatar answered Nov 17 '22 17:11

mik