Name, Phone, and Email

danejLead GenerationLeave a Comment

In this tutorial, we’ll be using Ruby 2+ and Rails 4+. We will create an online funnel with a landing page and a thanks page. Visiotrs will come to your landing page. You will ask them for their name, phone and email, and then deliver whatever you promised in exchange.

Create your new application

$ rails new name-phone-email
$ cd name-phone-email

Create a new Lead model, where you’ll keep those precious leads

$ rails g model Lead name:string phone:string email:string token:string

Create your unit tests

Be sure to install RSpec, Capybara, and FactoryGirl. These unit tests will cover your model. First, check if the object is valid after creating from a factory, and check any other validations that you put on the model.

#spec/models/lead_spec.rb
require 'spec_helper'

describe Lead do
  it "is valid with defaults" do
    FactoryGirl.build(:lead).should be_valid
  end

  it "is invalid without a name" do
    FactoryGirl.build(:lead, name: nil).should_not be_valid
  end

  it "is invalid without a phone" do
    FactoryGirl.build(:lead, phone: nil).should_not be_valid
  end
end

#spec/factories/leads.rb
FactoryGirl.define do
  factory :lead do
    name 'John Doe'
    sequence(:email) { |n| "email#{n}@lvh.me" }
    phone '800-555-1234'
  end
end

#Run your tests
$ bundle exec rspec spec

Update the model with your validations

#app/models/lead.rb
validates_presence_of :name
validates_presence_of :phone

Create your routes

#config/routes.rb
  get '/' => 'website#landing'
  post '/create' => 'website#create'
  get '/thanks/:token' => 'website#thanks', as: :thanks

#You can run `bundle exec rake routes` to see what they are

Create controller tests
For other great rails testing information, check out Everyday Rails.

Let’s write controller tests for the happy and very sad paths.

describe WebsiteController do
  describe "GET #landing" do
    it "renders the landing template" do
      get :landing
      response.should render_template :landing
    end
  end

  describe "POST #create" do
    context "with valid attributes" do
      it "creates a new lead" do
        expect {
          post :create, lead: FactoryGirl.attributes_for(:lead)
        }.to change(Lead, :count).by(1)
      end

      it "redirects to the thanks template" do
        post :create, lead: FactoryGirl.attributes_for(:lead)
        response.should redirect_to thanks_path(token: assigns(:lead).token)
      end
    end

    context "with invalid attributes" do
      it "does not save the lead in the database" do
        expect {
          post :create, lead: FactoryGirl.attributes_for(:invalid_lead)
        }.to_not change(Lead, :count)
      end

      it "re-renders the landing template" do
        post :create, lead: FactoryGirl.attributes_for(:invalid_lead)
        response.should render_template :landing
      end
    end
  end

  describe "GET #thanks" do
    it "assigns lead to @lead" do
      lead = FactoryGirl.create(:lead)
      get :thanks, token: lead.token
      expect(assigns(:lead)).to eq lead
    end

    it "should raise RecordNotFound" do
      expect {
        get :thanks, token: 'abc123'
      }.to raise_error(ActiveRecord::RecordNotFound)
    end
  end
end

Create your website controller

$ touch app/controllers/website_controller.rb

#app/controllers/website_controller.rb
class WebsiteController < ActionController::Base
  def landing
    @lead = Lead.new
  end

  def create
    @lead = Lead.new(lead_params)

    if @lead.save
      redirect_to thanks_path(@lead.token)
    else
      render :landing
    end
  end

  def thanks
    @lead = Lead.find_by_token!(params[:token])
  end

private
  def lead_params
    params.require(:lead).permit(:name, :phone, :email)
  end
end

Create your views

$ mkdir app/views/website
$ touch app/views/website/landing.html.erb
$ touch app/views/website/thanks.html.erb

Build your landing page
This is an example built with Bootstrap 3+. You can also use Foundation.

<%= form_for @lead, url: create_path do |f| %>
  <%= render 'shared/error_messages', target: @lead %>
  <div class="form-group">
    <%= f.label :name %>
    <%= f.text_field :name, class: 'form-control' %>
  </div>
  <div class="form-group">
    <%= f.label :phone %>
    <%= f.text_field :phone, class: 'form-control' %>
  </div>
  <div class="form-group">
    <%= f.label :email %>
    <%= f.text_field :email, class: 'form-control' %>
  </div>
  <div class="form-group">
    <%= f.submit "Get more info" %>
  </div>
<% end %>

Create the error_messages partial

$ mkdir app/views/shared
$ touch app/views/shared/_error_messages.html.erb

#app/views/shared/_error_messages.html.erb
<% if target.errors.any? %>
  <div id="error-explanation">
    <div id="please-correct">
      <span>Please Correct <%= pluralize(target.errors.count, "Error") %></span>
    </div>
    <ul>
      <% target.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
    </ul>
  </div>
<% end %>

We have included a token on our Lead model. To set this column before the lead is validated, let's create a before filter.

#app/models/lead.rb
class Lead < ActiveRecord::Base
  before_validation :generate_token, on: [:create]

  #other stuff ...

private
  def generate_token
    self.token = loop do
      random = SecureRandom.urlsafe_base64(nil, false)
      break random unless self.class.where(token: random).exists?
    end
  end
end

This will create a unique token that is used in our thanks path. Now, visitors won't be able to view the thanks page without a valid token.

Leave a Reply