#124 Beta Invitations

You know those invitation systems where a given user can invite a number of other people to join? That's what I show you how to make in this episode.

script/generate nifty_scaffold invitation sender_id:integer recipient_email:string token:string sent_at:datetime new
script/generate migration add_invitation_to_users invitation_id:integer invitation_limit:integer
script/generate mailer Mailer invitation

# models/invitation.rb
belongs_to :sender, :class_name => 'User'
has_one :recipient, :class_name => 'User'

validates_presence_of :recipient_email
validate :recipient_is_not_registered
validate :sender_has_invitations, :if => :sender

before_create :generate_token
before_create :decrement_sender_count, :if => :sender

private

def recipient_is_not_registered
  errors.add :recipient_email, 'is already registered' if User.find_by_email(recipient_email)
end

def sender_has_invitations
  unless sender.invitation_limit > 0
    errors.add_to_base 'You have reached your limit of invitations to send.'
  end
end

def generate_token
  self.token = Digest::SHA1.hexdigest([Time.now, rand].join)
end

def decrement_sender_count
  sender.decrement! :invitation_limit
end

# models/user.rb
validates_presence_of :invitation_id, :message => 'is required'
validates_uniqueness_of :invitation_id

has_many :sent_invitations, :class_name => 'Invitation', :foreign_key => 'sender_id'
belongs_to :invitation

before_create :set_invitation_limit

attr_accessible :login, :email, :name, :password, :password_confirmation, :invitation_token

def invitation_token
  invitation.token if invitation
end

def invitation_token=(token)
  self.invitation = Invitation.find_by_token(token)
end

private

def set_invitation_limit
  self.invitation_limit = 5
end

# invitation_controller.rb
def new
  @invitation = Invitation.new
end

def create
  @invitation = Invitation.new(params[:invitation])
  @invitation.sender = current_user
  if @invitation.save
    if logged_in?
      Mailer.deliver_invitation(@invitation, signup_url(@invitation.token))
      flash[:notice] = "Thank you, invitation sent."
      redirect_to projects_url
    else
      flash[:notice] = "Thank you, we will notify when we are ready."
      redirect_to root_url
    end
  else
    render :action => 'new'
  end
end

# users_controller.b
def new
  @user = User.new(:invitation_token => params[:invitation_token])
  @user.email = @user.invitation.recipient_email if @user.invitation
end

# routes.rb
map.signup '/signup/:invitation_token', :controller => 'users', :action => 'new'

# models/mailer.rb
def invitation(invitation, signup_url)
  subject    'Invitation'
  recipients invitation.recipient_email
  from       '[email protected]'
  body       :invitation => invitation, :signup_url => signup_url
  invitation.update_attribute(:sent_at, Time.now)
end

<!-- mailer/invitation.erb -->
You are invited to join our beta!

<%= @signup_url %>

<!-- invitations/new.html.erb -->
<% form_for @invitation do |f| %>
  <p>
    <%= f.label :recipient_email, "Friend's email address" %><br />
    <%= f.text_field :recipient_email %>
  </p>
  <p><%= f.submit "Invite!" %></p>
<% end %>

<!-- home/index.html.erb -->
<p>We are currently in private beta. Please submit your email address below, and we will notify you when we are ready to accept more users.</p>

<% form_for Invitation.new do |f| %>
  <p>
    <%= f.label :recipient_email, "Your Email:" %>
    <%= f.text_field :recipient_email %>
    <%= f.submit 'Submit' %>
  </p>
<% end %>

<!-- users/new.html.erb -->
<%= f.hidden_field :invitation_token %>

你可能感兴趣的:(html,F#,Flash)