Contact form in Rails 4

I’ve updated this article once again. While untimely, I hope it will still be as useful as the previous incarnation from 2011.

This tutorial shows and explains how to build a form that emails its submitted fields. Just follow the code examples for the quick version. For the long and explained version, read everything.

Before starting

This tutorial does not explain how to set up a mail server. It’s a tedious task, which is why I prefer to use Google Apps for managing email. For those interested setting one up, plenty of well–written articles are available around the web: here’s one from Linode, my hosting provider.

The list of prerequisites is simple.

  1. A mail server
  2. Ruby on Rails 4.2.0 (any 4.2.x will probably work)

Configuring the mail server with Rails

The application must be able to communicate with the mail server. Open config/application.rb and tell ActionMailer how to connect to the mail server. Modify the code as needed (this example configuration works for Google Apps).

For more details about the possible configuration options, see the official documentation on the ActionMailer.

config.action_mailer.smtp_settings = {
  address: "smtp.gmail.com",
  port: 587,
  domain: "<example.tld>",
  user_name: "<username>",
  password: "<password>",
  authentication: :plain,
  enable_starttls_auto: true
}

config.action_mailer.default_url_options = {
  host: "yourdomain.tld"
}

The host key under the default_url_options configuration of ActionMailer is the domain which any generated URLs show. For example, if the host was left as yourdomain.tld, then link_to(root_url, "Website") would generate <a href="http://yourdomain.tld/">Website</a> in a mailer’s view.

Modelling a message

Models in Rails provide a lot of functionality for free. There’s no point re–creating components like validations when they’re done so well already. ActiveModel is written in such a way that picking individual pieces of functionality and leaving the rest is simple. Create a new model to represent an email in app/models. I chose to call mine, Message.

class Message

  include ActiveModel::Model
  include ActiveModel::Conversion
  include ActiveModel::Validations

  attr_accessor :name, :email, :content

  validates :name,
    presence: true

  validates :email,
    presence: true

  validates :content,
    presence: true

end

The include method calls pick the bits of functionality from ActiveModel that I want. This example only validates that each attribute is present. Adding a format validation on the email address would be a good improvement.

The mailer class

The mailer for sending messages is simple. Run rails g mailer MessageMailer to generate the files. Open up message_mailer.rb in app/mailers and add a new_message method.

class MessageMailer < ActionMailer::Base

  default from: "Your Mailer <noreply@yourdomain.com>"
  default to: "Your Name <your.email@yourdomain.com>"

  def new_message(message)
    @message = message
    
    mail subject: "Message from #{message.name}"
  end

end

Replace the necessary bits of configuration as needed.

Template for the email

Create the file new_message.text.erb in app/views/message_mailer. This is the template used for the email. Mine is bland. Make it better.

<%= @message.name %> <<%= @message.email %>> wrote:

<%= @message.content %>

Controller and routes

I try to stick with convention when it makes sense. Because of that, controller is ‘RESTful’ in the Rails sense of the word. Run rails g controller messages to generate the necessary files. Open message_controller.rb to add new, and create actions.

class MessagesController < ApplicationController

  def new
    @message = Message.new
  end

  def create
    @message = Message.new(message_params)
    
    if @message.valid?
      MessageMailer.new_message(@message).deliver
      redirect_to contact_path, notice: "Your messages has been sent."
    else
      flash[:alert] = "An error occurred while delivering this message."
      render :new
    end
  end

private

  def message_params
    params.require(:message).permit(:name, :email, :content)
  end

end

Notice that instead of the typical if @message.save?, it checks for validity instead.

Routes

Here I break away from the convention of routes such as, /messages/new, and, /messages. Instead, I wanted everything under, /contact. I added two lines in my config/routes.rb to accomplish that.

get 'contact', to: 'messages#new', as: 'contact'
post 'contact', to: 'messages#create'

Under /contact, all GET requests call MessagesController#new, and all POST requests call MessagesController#create.

The form template

Create the file new.html.erb in app/views/messages. The code that goes in this file is entirely dependent on the application’s layout. I just copied this code from my own template.

<%= form_for @message, url: contact_path do |message_form| %>
  <fieldset>
    <div class="field">
      <%= message_form.text_field :name, placeholder: "Name" %>
    </div>
    
    <div class="field">
      <%= message_form.email_field :email, placeholder: "Email"%>
    </div>
    
    <div class="field">
      <%= message_form.text_area :content, placeholder: "Message"%>
    </div>
  </fieldset>
  
  <fieldset>
    <div class="field">
      <%= message_form.submit "Send" %>
    </div>
  </fieldset>
<% end %>

Try it

Run rails server and navigate to /contact. Fill out and submit the form!

Website updates

It’s been a long time—years in fact—since I last updated my website. Despite the relative silence during that time on my part, a lot happened.

A new design

Without a doubt, the previous design was dated. It was crafted just before HTML5 and responsive design became main–stream. This new design is simple. It’s purpose is to let the reader focus on the content, and nothing more. There are still some major pieces of functionality I’d like to add, and a number of ideas I want to experiment with.

Updated software

In truth, I abandoned my old publishing system. I meant to keep it up–to–date, and see it evolve over time. However, that just wasn’t the case. My new system uses some code from the old one, but for the most part, it is brand new. As a result, I’ll be publishing a new tutorial on building a, ‘contact’, form using Rails 4 (ETA ).

HTTPS is becoming more and more popular. Soon, it will even have a role in search rankings. I attended a fantastic talk at Google I/O 2014 which inspired me to start making the switch. My entire site can now be browsed securely, and it will eventually become the default (I just need to work out a few bugs first).

Everything else

A lot happened in the last few years. Academia continues to be my life. In the time that passed, I earned both a certificate and diploma in computer systems technology. The next 3 to 4 years of my life are in pursuit of a degree. My interests are with computer science, but I’m studying towards a degree in geomatics. A multi–disciplined education is more interesting to me (and more useful in general).

It’s safe to expect more updates from now on. There’ll be a ramp–up period as I work on content to publish. I’m not sure how often a new post will be up, and I don’t want to commit to an unrealstic schedule. So for now, I’ll just let things happen as they will.

Contact form in Rails 3

Please refer to the new version of this article for Rails 4.

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.

git-push with specific SSH key

I figured this was worth a post, as I’ve never ran into this problem before. I’ve been working on setting up a server, to which I connect using RSA. The standard name for an RSA key file is id_rsa(.pub). However, as I use my ‘standard’ key elsewhere, I wanted to use a specific key for this server.

Connecting via SSH to the server with the key is as simple as adding -i /path/to/key. The problem arose when I needed to be able to push to a Git repository hosted on the server, and adding -i to git-push doesn’t work.

The solution was to add a Host directive to my ~/.ssh/config file. Then, use that Host to connect to when push’ing to the remote server.

If it doesn’t exist, create the file ~/.ssh/config. Add the following to it, editing where necessary.

Host RemoteServer
  HostName remote-server.tld
  User git
  IdentityFile ~/.ssh/remoteserver_key

Remember to reload SSH after creating this file. This example config would be the equivalent of running a command like ssh git@remote-server.tld -i ~/.ssh/remoteserver_key. You can even run ssh RemoteServer to test the connection out.

In your Git repository, add a new remote repository. Here I’ve called it origin, as the convention might have it.

git remote add origin RemoteServer:path/to/repository.git

Instead of specifying a user @ a domain, it uses the name of the Host in the SSH config. The path/to/repository.git is relative, on the average system, that will probably point to /home/git/path/to/repository.git.

Try running a git push origin master to see if it works!

Exception notification for Rails 3

Using the popular ExceptionNotification plugin has changed slightly in Rails 3. One thing to note is that the official repository has moved from the Ruby on Rails GitHub organization to Sebastian Martinez’s account. Let’s get started.

Add the gem to an applications Gemfile.

gem 'exception_notification'

Then install the actual gem with either, gem install exception_notification, or by running bundle install from the application’s root.

Open the environment configuration file for which the application requires exceptions being reported from, typically this is config/environments/production.rb. Inside the application’s configure block, place the following code, editing where necessary.

# For a full list of configurable options, see the gem's GitHub home page.
config.middleware.use ExceptionNotifier,
  :email_prefix => "[Application Name] ",
  :sender_address => %{ "Application Name" <noreply@application-name.ca> },
  :exception_recipients => %w{ recipient.1@application-name.ca }

When the application is running on production, and assuming it’s set up with an email server, it will send the proper notification when an error occurs!