(A Better) Contact Form in Rails
Tuesday, September 1st, 2009 · 3 comments
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.

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