Skip to content

Invites and Clearance (Rails 3)

gabebw edited this page Apr 15, 2011 · 5 revisions

NOTE: This page is very similar to the Invites and Clearance page, except that this page updated the code samples for Rails 3, while the other page contains code appropriate for Rails 2.

Clearance doesn’t support invitation codes but they are easily added.

The techniques described here were developed while building s3analytics.com and will cover:

  • Why invitation codes are useful
  • Requiring an invite code
  • Testing the User creation process

Why invitation codes are useful

In layman’s terms:

Invitation codes are useful for controlling the number of accounts created in a new web service. This is especially important since it will allow a team to roll out fixes and enhancements and respond to user feedback in a timely fashion, ultimately delivering users the best possible experience.

By default, Clearance lets anyone sign up for a new account. The next two sections will describe how to override that behavior.

Requiring an invite code

Users require a redeemable Invite to successfully register an account.

1. Create an “invite” resource.
$ rails generate scaffold invite

2. Open up the migration and add the following fields and indexes:

def self.up
  create_table :invites do |t|
    t.string :firstname
    t.string :lastname
    t.string :email
    t.string :invite_code, :limit => 40
    t.datetime :invited_at
    t.datetime :redeemed_at
    t.index [:id, :email]
    t.index [:id, :invite_code]
  end
end

In layman’s terms:
An Invite may only be redeemed once. It keeps track of when an Invite was delivered and when it was redeemed.

For the full Invite model, see http://gist.github.com/90543.

Run the migration:

$ rake db:migrate

3. Once we have the Invite model in place, we’ll need to modify the existing InvitesController to lockdown actions, send emails, and list invites.

Lockdown admin actions

Since we have the rule that anyone should be able to create Invites, but only Admins may modify or delete them, one quick and dirty way we can lock the controller down is with a before_filter, like so:

before_filter :access_for_admin, :except => [:new, :create]

Where the access_for_admin method contains logic that enforces an admin policy on a resource. i.e. it uses HTTP 401, or ensures a user has the correct ACL.

Sending emails

To send emails, we’ll need to add a few routes to config/routes.rb, namely send_invitation and redeem_invitation:

match '/send_invitation/:id' => 'invites#send_invitation', :as => 'send_invitation'
match '/signup/:invite_code' => 'users#new', :as => 'redeem_invitation'

Before we can send email, we have to create a mailer. If you have a mailer already, skip to the “Defining an invite method for our mailer” below.
To generate the mailer with a dummy invite method:
$ rails generate mailer InvitationMailer invite

Defining an invite method for our mailer
Edit app/mailers/invitation_mailer.rb (or whichever mailer you’re using) so that the invitation method looks like this:

def invite(invitation)
  @invite = invitation
  mail :from => 'DO_NOT_REPLY',
       :to => invitation.email,
       :subject => "Welcome to S3 Analytics"
end

Now open up app/views/invitation_mailer/invite.html.erb (NOT invite.text.erb) in your favorite editor and put in a link to the invite redemption page:
<%= redeem_invitation_url(@invite.invite_code) %>

The send_invitation action in InvitesController looks like this:

def send_invitation
  @invite = Invite.find(params[:id])
  @invite.invite!
  mail = InvitationMailer.invite(@invite)
  mail.deliver
  redirect_to(invites_url, :notice => "Invite sent to #{@invite.email}")
end

Listing invites

To list invites, we’re going to add an additional column to the index view on the InvitesController. In Haml:

%td
  - if invite.invited?
    Invited
  - else
    = link_to 'Invite', send_invitation_path(invite), :confirm => 'Send invitation? ', :method => :post

4. Once we have the emails in place, we’ll need to subclass Clearance::UsersController to support invitation based registrations. We do this by overriding the create action, as in this gist: http://gist.github.com/85380.

5. And finally, we’ll add a form which invites visitors to enter their name and email. I left this bit out since it’s pretty much a boilerplate Rails form helper.

Attribution

This idea was lifted from S3 Analytics and written up by Marc Chung.