Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top