This is an updated version of a tutorial I originally wrote in 2008 on building a contact form with Ruby on Rails.

The goal of this tutorial is to build a form that when submitted will validate and email the data.

Prerequisites

To simplify this, I’m just using Google Apps to manage email addresses. If you have your own email server just modify the settings as needed. To get started you’ll need:

  1. A Google Apps account, of course
  2. Ruby on Rails 3.2.2 (give or take a few version numbers)

Configuring Rails for GMail

In an existing or new application, open config/application.rb. Insert the following snippet in the Application class.

config.action_mailer.smtp_settings = {
  :address              => "smtp.gmail.com",
  :port                 => 587,
  :domain               => "yourdomain.dev",
  :user_name            => "from@yourdomain.dev",
  :password             => "Super-Secure-Password",
  :authentication       => :plain,
  :enable_starttls_auto => true
}

config.action_mailer.default_url_options = {
  :host => "yourdomain.dev"
}

Set the value of :domain to the domain you’re using for Google Apps, and :user_name and :password to your Google Apps account credentials. In the second block replace :host with the domain where the application is reachable from. The :host option is used to ensure that all links in email templates generate full URLs.

The Message Model

To allow validation of the message, I create a model and just include ActiveModel’s validations. Allowing the model to be written just like any other Rails model.

Create the file app/models/message.rb, or with a name of your choice. Make the file look similar to the following.

class Message

  include ActiveModel::Validations
  include ActiveModel::Conversion
  extend ActiveModel::Naming

  attr_accessor :name, :email, :subject, :body

  validates :name, :email, :subject, :body, :presence => true
  validates :email, :format => { :with => %r{.+@.+\..+} }, :allow_blank => true
  
  def initialize(attributes = {})
    attributes.each do |name, value|
      send("#{name}=", value)
    end
  end

  def persisted?
    false
  end

end

This is fairly self explanatory. A message can have a subject and body, as well as the name and email address of the sender. All of the fields are required, and the email address is verified with a regular expression.

The Mailer Model and Views

Run rails g mailer NotificationsMailer. This generates app/mailers/notifications_mailer.rb.

We'll want notifications_mailer.rb to look similar to this snippet. Check out the ActionMailer API for specifics on what’s happening here.

class NotificationsMailer < ActionMailer::Base

  default :from => "noreply@youdomain.dev"
  default :to => "you@youremail.dev"

  def new_message(message)
    @message = message
    mail(:subject => "[YourWebsite.tld] #{message.subject}")
  end

end

Replace :to, :from and :subject with the address you’d like the email sent to, the address it’s being sent from (should be the one you configured the Rails application with), and the subject of the email.

Create the file:

app/views/notifications_mailer/new_message.text.erb

How the message looks is entirely up to you. Here’s an example of how it could be laid out.

Name: <%= @message.name %>

Email: <%= @message.email %>

Subject: <%= @message.subject %>

Body: <%= @message.body %>

The Controller and View

Run rails g controller contact and then open app/controllers/contact_controller.rb.

The controller will only need two actions: new and create.

class ContactController < ApplicationController

  def new
    @message = Message.new
  end

  def create
    @message = Message.new(params[:message])
    
    if @message.valid?
      NotificationsMailer.new_message(@message).deliver
      redirect_to(root_path, :notice => "Message was successfully sent.")
    else
      flash.now.alert = "Please fill all fields."
      render :new
    end
  end

end

To get these actions working, open up config/routes.rb and insert the following two lines.

match 'contact' => 'contact#new', :as => 'contact', :via => :get
match 'contact' => 'contact#create', :as => 'contact', :via => :post

When a GET request is made to /contact, the new action is called. When a POST request is made to /contact, the create action is called.

Create app/views/contact/new.html.erb. As with the email template, this template is entirely up to you, I'm only providing an example of what it could look like.

<%= form_for @message, :url => contact_path do |form| %>
  <fieldset class="fields">
    <div class="field">
      <%= form.label :name %>
      <%= form.text_field :name %>
    </div>
    
    <div class="field">
      <%= form.label :email %>
      <%= form.text_field :email %>
    </div>
    <div class="field">
      <%= form.label :subject %>
      <%= form.text_field :subject %>
    </div>
    
    <div class="field">
      <%= form.label :body %>
      <%= form.text_area :body %>
    </div>
  </fieldset>
  
  <fieldset class="actions">
    <%= form.submit "Send" %>
  </fieldset>
<% end %>

Try it

Start your rails server and go to /contact. Fill out the form and hit send. If everything was done correctly an email should arrive in the inbox of the address specified.