I'm trying to layout a Rails app using Devise for authentication. I'd like to have an initial landing page where people could enter then email address. I'd like to create an account as soon as I get the email address and then let the user finalize the authentication process later. Is there some documentation that would would show how to do this?
Thanks!
I ended up solving this by using the "devise_invitable" gem. The only thing that I had to extend to get this working was to make sure that a user didn't need to be authenticated to send an invitation. Over-ride the invitations contoller and it's working great:
class InvitationsController < Devise::InvitationsController
include Devise::Controllers::InternalHelpers
skip_filter :authenticate_inviter!
skip_filter :authenticate!
def current_inviter
@current_inviter ||= User.new(params[:user])
end
end
I'm not sure if there is good documentation for how to do this, but it would not be hard. Just don't require authentication on your landing page, or on the post from the login form on that page. Collect an email address in the login form. Send the user a mail to the address they log in with. In the email, include the 'forgot password' link (renamed to 'click here to sign in' ... or whatever) to force the user to login and choose a password. Does that work for you, or did i miss something?
I realize this is late, but this might be helpful to others. I had a similar requirement as you. Basically, I wanted to have a user enter an email address, and persist the user as a guest. Once the user is promoted to a 'regular' user, I re-enable password authentication. First, I created a warden strategy based on the devise-gullible gem. I made a modification to the authenticate
method:
class Guest < Authenticatable
def authenticate!
resource = mapping.to.find_for_database_authentication(authentication_hash)
if resource
if resource.respond_to?(:guest?) and resource.guest?
success!(resource)
else
fail(:regular_user)
end
else
fail(:invalid)
end
end
end
I define a guest user in my user model as follows:
def guest?
self.roles.length == 0
end
I'm using CanCan with devise and a HABTM to handle the roles. Currently, I have a 'regular' user and an 'admin' user. A user is a guest if he has no assigned roles yet.
Then, you need to override the devise registrations controller:
class Users::RegistrationsController < Devise::RegistrationsController
prepend_before_filter :allow_params_authentication!, :only => :create
def create
resource = warden.authenticate(:guest,
{ scope: resource_name,
recall: "#{controller_path}#new" })
if resource
set_flash_message(:notice, :signed_in) if is_navigational_format?
sign_in(resource_name, resource)
respond_with resource, :location => after_sign_in_path_for(resource)
elsif warden.winning_strategy.message == :regular_user
set_flash_message :notice, :regular_user if is_navigational_format?
redirect_to new_session_path(resource_name)
else
super
end
end
end
Note that the idea is that we attempt to authenticate a user running the guest strategy only. If he is already registered as a guest, just sign him in normally. If the guest strategy fails because he is registered, but is now a regular user, redirect to the normal sign in page.
Now it is possible to persist some limited information I may wish to collect from a guest, and not require him to have to do a full sign up. I use a normal User model:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :omniauthable,
:token_authenticatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
has_and_belongs_to_many :roles
def self.new_with_session(params, session)
super.tap do |user|
if user.password.blank?
user.password = Devise.friendly_token[0,31]
# Also, we don't need to do email confirmation in this case.
# The user will have the guest role, and we'll do a confirmation
# when we promote him to a 'regular' user.
user.skip_confirmation!
end
end
end
def has_role?(role)
!!self.roles.find_by_name(role.to_s.camelize)
end
end
Note that I auto-generate a password in build_with_session
. You can send a auth token at the time of your choosing, and then require the user to set a new password at that time. You'll also want to then change his role so that he becomes a regular user (or do whatever it is you want to note he is no longer a guest).
Here's my partial that appears on the front page:
<%= simple_form_for(resource,
as: resource_name,
url: user_registration_path,
defaults: { required: false },
html: { class: 'well' },
wrapper: :bootstrap,
validate: true) do |f| %>
<%= f.error_notification %>
<fieldset>
<legend>New here? Let's get started!</legend>
<%= f.input :email, placeholder: '[email protected]', validate: { uniqueness: false } %>
<%= f.button :submit, "Get my quote!", class: 'btn-primary' %>
</fieldset>
<% end %>
So, this form functions as both a guest registration and login form. The only think I don't really care for so far is the the registrations controller is handling an authentication, but I didn't see an immediate way around this.
I implemented this strategy in my local lib directory. Be sure to set your load path appropriately, and add require 'devise_guest'
to config/initializers/devise.rb
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With