UPDATE
I have further clarified my question, listed at the end of this post.
Problem Summary:
I am trying to implement lazy (aka soft sign-up) registration in Devise via an emailed URL which includes token authentication. On my site, a User has_many :payments, and a Payment belongs_to :user. When a User creates a new Payment, it includes the attribute :email which represents a new non-registered user (which I'll call "Guest"). I use ActionMailer to send an email to this new Guest.
In this email that is sent, I would like to include a URL with token authentication (e.g. http://localhost/index?auth_token=TOKENVALUE), so that the Guest can see and edit views that require authentication and are specifically customized to them (based on their :email). The Guest should also have the ability to register as a User - since I already have their email address, they would just need to provide a password.
My Progress So Far:
- I have implemented the ability for someone to register for the site using Devise and created the associated views, model and controller to make changes to my
Paymentmodel - I have setup ActionMailer and am using it to send emails, but have not yet setup token-authentication as I'm not sure how to do so given my use case above
Related Resources:
- https://github.com/plataformatec/devise/wiki/How-To:-Simple-Token-Authentication-Example
- http://zyphdesignco.com/blog/simple-auth-token-example-with-devise
- Multiple user models with Ruby On Rails and devise to have separate registration routes but one common login route
- how to create a guest user in Rails 3 + Devise
- https://github.com/plataformatec/devise/wiki/How-To:-Create-a-guest-user
- http://blog.bignerdranch.com/1679-lazy-user-registration-for-rails-apps/
- http://railscasts.com/episodes/393-guest-user-record?view=asciicast
- https://github.com/plataformatec/devise/wiki/How-To:-Manage-users-through-a-CRUD-interface
- Rails 3 - Devise Gem - How to Manage Users through CRUD interface
- http://danielboggs.com/articles/rails-authentication-and-user-management-via-crud/
/app/models/payment.rb
class Payment < ActiveRecord::Base
attr_accessible :amount, :description, :email, :frequency, :paid, :user_id
belongs_to :user
validates :email, :presence => true, :format => { :with => /.+@.+\..+/i }
validates :amount, :presence => true
validates :description, :presence => true
end
/app/models/user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :confirmable
# I will also need to add ":token_authenticatable"
attr_accessible :email, :password, :password_confirmation, :remember_me
has_many :payments
end
Questions:
- How can I keep my
Usertable in sync with newPaymentsthat are created, such that any new:emailcreated in thePaymenttable automatically are added in theUsertable as an:email? - Following from question 1, the new
Usercreated should include a token but not include a password, since the User has not yet registered for the site. Should I create the newUserwith a blank password, randomly generated string, or other? In either case, I think they would need to come to the registration page from their token-authenticated URL to prevent others from registering under their email username (e.g. lazy registration) - Following from question 2, I think that I will need to distinguish between Guests and normal users, as some of the views will change depending on user type. Is there a preferred method other than adding a column that would have a 0 or 1 to delineate between the two user types?
My preference if possible is to use Devise since I am using many of the features included. I'm new to RoR and appreciate any advice you can provide!
EDIT: Here is the code I used to address question #1 above, in my payments controller, in case helpful to someone else
def create
@payment = current_user.payments.build(params[:payment])
#Here is the code I added to keep User :email in sync with Payment :email, without token authentication implemented yet
unless User.find_by_email(params[:payment][:email].downcase)
u = User.new({:email => params[:payment][:email].downcase, :password => nil, :password_confirmation => nil })
u.skip_confirmation!
u.save(:validate => false) #skip validation
end
respond_to do |format|
if @payment.save
format.html { redirect_to payments_url, :flash => { notice: 'Payment was successfully created.' } }
format.json { render json: @payment, status: :created, location: @payment }
else
format.html { render action: "new" }
format.json { render json: @payment.errors, status: :unprocessable_entity }
end
end
end