(A Better) Contact Form in Rails

This is an update to my original guide on creating a "Contact Us" form that sends out an email with Ruby on Rails.

These are instructions for creating a form that takes user input and emails it. Or you could just call it a contact/feedback form. They're useful for collecting data from users.

Prerequisites

To get started on the right foot (no pun intended, and no offense to those left legged people), you'll probably want the following:

  • Ruby on Rails - I'm using the latest version of Rails as of this writing, version 2.3.4
  • Email Server - I'll leave this up to you, though Slicehost has some great articles on how to set up an email server

Step 1: The Setup

Open config/environment.rb in your Rails application. On a fresh app it looks something like this:

# Be sure to restart your server...
# ...
Rails::Initializer.run do |config|
  # ...
end

Inside of the Rails::Initializer.run block, add the following code at just before the block end's. You'll need to modify the settings to suit your mail servers configuration.

config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
  :address        => 'email-server.com',
  :port           => 25,
  :domain         => 'email-server.com'
}

See ActionMailer::Base under "Configuration options" for details on how to connect to your mail server.

Step 2: The Model

Now that Rails is aware of the mail server, it's time to create the mailer model.

./script/generate mailer Notifications

This will create app/models/notifications.rb, a blank class that extends ActionMailer::Base. Let's add some magic beans to it.

class Notifications < ActionMailer::Base
  def contact(email_params)
    subject "[My Website] " << email_params[:subject]
    recipients "myemail@mydomain.ca" # Replace with your address
    from email_params[:email]
    sent_on Time.now.utc

    body :message => email_params[:body], :name => email_params[:name]
  end
end

Pretty cool huh?

Step 3: The Controller

The controller is almost as simple as the model.

./script/generate controller contact

Only two methods are required inside the ContactController.

def index
  # render index.html.erb
end

def create
  if Notifications.deliver_contact(params[:contact])
    flash[:notice] = "Email was successfully sent."
    redirect_to(contact_path)
  else
    flash.now[:error] = "An error occurred while sending this email."
    render :index
  end
end

Now for...

Step 4: The Routes

Let's add some routes to make our controller call the right actions.

map.with_options :controller => 'contact' do |contact|
  contact.contact '/contact',
    :action => 'index',
    :conditions => { :method => :get }

  contact.contact '/contact',
    :action => 'create',
    :conditions => { :method => :post }
end

When a user hits /contact with a GET request, the app will call the index action. When they hit it with a POST request, it will call the create action, almost like a resource!

Step 5: The View

Create and open app/views/contact/index.html.erb. Make it look something similar to this:

<% form_for(:contact, :url => contact_path) do |form| %>
  <p>
    <%= form.label :subject %><br />
    <%= form.text_field :subject %>
  </p>

  <p>
    <%= form.label :name %><br />
    <%= form.text_field :name %>
  </p>

  <p>
    <%= form.label :email %><br />
    <%= form.text_field :email %>
  </p>

  <p>
    <%= form.label :body %><br />
    <%= form.text_area :body %>
  </p>

  <p>
    <%= form.submit "Send" %>
  </p>
<% end %>

Now we need to write the view for our email. Create and open app/views/notifications/contact.erb. With that body method in our model, the view has access to the @message and @name instance variables.

A simple view could look like this:

<%= @name %> wrote you an email:

---
<%= @message %>
---

Step 6: Play

Start your web server and navigate to /contact, you should see the form we just wrote in Step 5. Fill it out and hit "Send", if all is well, there should be an email sitting in your inbox.

Filed in Tutorials.

Michael

September, 1st, 2009 at 2230

Works great! Thank you so much. I spent over 3 hours today trying to figure this out. Also, just fyi... if anyone just copies and pastes the code. Under Step 5: form.text_field for email is a typo, will give you an error. Make sure field is with an ie not ei ;)

Thank you again!

Mat Harvard

September, 1st, 2009 at 2305

Typo fixed, thanks for the heads-up Michael!

John

September, 2nd, 2009 at 1312

Great article.

It would be great, if you could some validations. Especially for those who are new to ROR like me.

Thanks