4

I'm trying to create a mailer that sends out an email whenever a user signs up. Pretty simple but I'm new to rails.

I have a site that already creates the user. I have a login and sign up page that works correctly, but need some help creating a mailer that sends out an email confirmation link and possibly an option to send out these emails without the user signing up like make a separate page for user invitations.

I've generated a model invitation.rb

  class Invitation < ActiveRecord::Base
  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 
  #attr_accessible :sender_id, :recipient_email, :token, :sent_at
end

and my invitiation_controller.rb

class InvitationsController < ApplicationController
  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
end

What else do I need to edit? how do I hook this up to an already existing user signup and login that is working fine?

Chris R
  • 45
  • 1
  • 5

2 Answers2

2

You should already have a UsersController or something like that for registration purposes, which you currently access through the signup_url named route. Suppose that this route is now something like:

http://localhost:3000/register/code_here

All you have to do now is check for the invitation in the controller action and process it accordingly like so:

def new
  invite = Invite.find_by_token(params[:id]

  if invite.nil?
    redirect_to root_path, :notice => "Sorry, you need an invite to register"
  end

  @user = User.new(:email => invite.recipient_email)

end

def create
  invite = Invite.find_by_token(params[:token]

  if invite.nil?
    redirect_to root_path, :notice => "Sorry, you need an invite to register"
  end

  begin

    invite.nil.transaction do
      invite.nil.destroy!
      @user = User.create(params[:user)
    end

    redirect_to my_dashboard_path, :notice => "Yay!"

  rescue ActiveRecord::RecordInvalid => invalid
     render :new, :alert => "Validation errors"
  end

end

Without the invite code, you will simply redirect to root page. You may want to DRY that check though. When someone uses the invite code, you may want to delete it from the database. I wrapped it up in a transaction, but this is up to you (creating the user may be more important).

If you want to create a page that allows users to create invitations without signing up, then simply don't add authentication to InvitationsController and update this snippet:

def create

  @invitation = Invitation.new(params[:invitation])
  @invitation.sender = current_user if logged_in?

  if @invitation.save

    Mailer.deliver_invitation(@invitation, signup_url(@invitation.token))
    flash[:notice] = "Thank you, invitation sent."

    if logged_in?
      redirect_to projects_url
    else
      redirect_to root_url
    end

  else
    render :action => 'new'
  end

end

I'm not sure if I covered all the bases, but I think this should point you in the right direction at least.

Jaryl
  • 2,561
  • 1
  • 24
  • 33
  • yes! thank you this is exactly what I'm trying to do. well just want to get an email sent out with something anything saying you've signed up. maybe im going about this the wrong way with the invitation thing. I don't really want to have to send out an invitation for them to sign up, just when they sign up they get the confirmation email. the invite can come later. so if I wanted it to just send out a confirmation email, can I use this same code I already made (from a railscast) to send out a confirm email? where would I and what would i need to put into my user_controller? – Chris R Dec 15 '11 at 19:44
  • Yes, though you would do well to create two tokens (one for invitations and the other for registrations). The process is the same, except that perhaps you could add another action to handle confirmation email links. – Jaryl Dec 17 '11 at 14:24
1

I can not see where Mailer.deliver_invitation comes from, do you use a gem? would it help if you would create mailer.rb, do you have any error mgs/ stack trace?

Have a look here there are some guides, 5 Action Mailer Configuration http://guides.rubyonrails.org/action_mailer_basics.html

Consider using devise for user authentication, https://github.com/plataformatec/devise It is complex, but well documented and easy to configure to jump start.

I assume you are using Rails 3.1 (works also in earlier versions, just find the right guide to your Rails version, to be sure)

vik
  • 762
  • 1
  • 7
  • 18
  • devise is installed on this site I inherited but am unfamiliar with it and am having a hard time configuring it which is why I was trying to just create this mailer by myself. any input with devise on how to easily set up a simple automatic email confirmation when someone signs up would be a great help. thank you ALL for the quick responses! – Chris R Dec 15 '11 at 19:47
  • First start would be their [github](https://github.com/plataformatec/devise) and then the **Wiki**. Here is another example using rspec and cucumber, but skip that for the moment, so you just use the tutorial for [customizing devise] (https://github.com/RailsApps/rails3-devise-rspec-cucumber/wiki/Tutorial) - rspec/cucumber is maybe a nice to have for you. – vik Dec 16 '11 at 08:52