Create a Rails 4 site with a simple contact us form
a complete tutorial
Contents
This tutorial uses Twitter Bootstrap, bootstrap-sass, SimpleForm, MailForm, and Guard. If you are familiar with Rails basics and bootstrap-sass, you can skip to the Add contact us form section
1. Create a Rails 4 Project
$ rails new project_name
$ cd project_name
Edit Gemfile
. Add the following gems.
# Front-end {
gem 'bootstrap-sass', '~> 2.3.2.0'
gem 'haml-rails', '~> 0.4.0'
# }
# Forms, mail {
gem 'mail_form', '~> 1.5.0.rc'
gem 'simple_form', '~> 3.0.0.rc'
# }
# Development (Optional) {
gem 'better_errors', group: :development
gem 'quiet_assets', group: :development
# }
# Development Guard {
gem 'guard-rails', group: :development
gem 'guard-livereload', group: :development
gem 'rack-livereload', group: :development
gem 'guard-bundler', group: :development
# }
See the example Gemfile with extra gems such as pg, bootswatch, heroku, font awesome
Install gems by running
$ bundle install
Setup guard
We use guard to automate gem installations, livereload, rails server restarts, etc.
Add guard definition to your Guardfile by running
$ guard init rails bundler livereload
You should see
08:21:14 - INFO - rails guard added to Guardfile, feel free to edit it
08:21:14 - INFO - bundler guard added to Guardfile, feel free to edit it
08:21:14 - INFO - livereload guard added to Guardfile, feel free to edit it
Booting Rails server with guard
Start Rails server and livereload by running
guard
Visit http://localhost:3000 in your browser. You should see the default Rails welcome page.
2. Create a home controller
rails g controller home index
Edit config/routes.rb
Replace get "home/index"
with root "home#index"
So that when you visit http://localhost:3000, the request will be handled by the home controller.
After saving the file, guard should restart your Rails server. Check if there’s any errors in the guard console. Visit http://localhost:3000 and you should see
3. Add styles
Add Bootstrap JavaScript and SCSS
We need some styles! Let’s add Twitter bootstrap.
Add in config/application.rb
config.assets.precompile += %w(*.png *.jpg *.jpeg *.gif)
Rename app/assets/stylesheets/application.css
to app/assets/stylesheets/application.css.scss
Add in app/assets/stylesheets/application.css.scss
@import "bootstrap";
Add in app/assets/javascript/application.js
, before //= require_tree .
//= require bootstrap
The page should now look like
Convert erb to Haml
The default Rails uses erb. Now we convert it to haml by html2haml
You can install html2haml as:
$ gem install html2haml
Convert the default layout in erb to haml
cd app/views/layouts
html2haml application.html.erb > application.html.haml
Remove the erb file
rm application.html.erb
Add Bootstrap HTML and navigation bar
Edit app/views/layout/application.html.haml
Add between %body
and =yield
.navbar.navbar-fixed-top
.navbar-inner
.container
%button.btn.btn-navbar{"data-target" => ".nav-collapse", "data-toggle" => "collapse", :type => "button"}
%span.icon-bar
%span.icon-bar
%span.icon-bar
%a.brand{:href => root_url}
brand
.nav-collapse.collapse
%ul.nav.pull-right
%li
= link_to t('Contact'), "todo"
Because we are using fixed navbar in this example, append app/assets/stylesheets/application.css.scss
body {
padding-top: $navbarHeight + 20px;
}
Edit app/views/home/index.html.haml
.container
.row
.span12
%h1 Home#index
%p Find me in app/views/home/index.html.haml
Your page should look like this now.
4. Add contact us form
Run the simple_form generator
rails g simple_form:install --bootstrap
Controller
rails g controller contacts
Edit config/routes.rb
, remove the generated routes for contacts
. Add
resources "contacts", only: [:new, :create]
Replace app/controllers/contacts_controller.rb
with
class ContactsController < ApplicationController
def new
@contact = Contact.new
end
def create
@contact = Contact.new(params[:contact])
@contact.request = request
if @contact.deliver
flash.now[:error] = nil
flash.now[:notice] = 'Thank you for your message!'
else
flash.now[:error] = 'Cannot send message.'
render :new
end
end
end
Model
Create app/models/contact.rb
with
class Contact < MailForm::Base
attribute :name, :validate => true
attribute :email, :validate => /\A([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})\z/i
attribute :message
attribute :nickname, :captcha => true
# Declare the e-mail headers. It accepts anything the mail method
# in ActionMailer accepts.
def headers
{
:subject => "My Contact Form",
:to => "your_email@example.org",
:from => %("#{name}" <#{email}>)
}
end
end
(Trimmed version of the MailForm example)
Views
Create app/views/contacts/new.html.haml
with
.container
%h1 Contact
= simple_form_for @contact, :html => {:class => 'form-horizontal' } do |f|
= f.input :name, :required => true
= f.input :email, :required => true
= f.input :message, :as => :text, :required => false, :input_html => {:rows => 10}
.hidden
= f.input :nickname, :hint => 'Leave this field blank!'
.form-actions
= f.button :submit, 'Send message', :class=> "btn btn-primary"
Create app/views/contacts/create.html.haml
with
.container
%h1 Thank you for your message.
%p We'll get back to you soon.
Add in app/assets/stylesheets/application.css.scss
.hidden { display: none; }
Edit app/views/layout/application.html.haml
, add/edit the menu item
%li
= link_to t('Contact'), new_contact_path
Add flashes just after the %body
.container
- flash.each do |name, msg|
- if msg.is_a?(String)
%div{:class => "alert alert-#{name == :notice ? "success" : "error"}"}
%a.close{"data-dismiss" => "alert"}
×
= content_tag :div, msg, :id => "flash_#{name}"
Results
Open http://localhost:3000/contacts/new in your browser
You should see the working contact us form with server-side validations.
For real e-mail delivery, you should set up SMTP in the environment settings.
Bonus / Further readings
- Add tests for mail delivery
- Add sidekiq, resque, or delayed_job for background mail delivery
- Add bootswatch-rails for easy theming.
- Use Rails Apps Composer for automations