#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 %>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章