Rails 4 Simple Form and Mail Form To Make Contact Form

In this tutorial I will be using the following gems:

  • Rails 4
  • mail_form 1.5
  • simple_form 3
  • Twitter Bootstrap

This tutorial will assume that you already have twitter bootstrap installed have your mailer configured. If your mailer is not configured you can look at this post to set it up using local environment variables: Setting Up Mailer Using Devise For Forgot Password

I will show you how to set up a simple contact form which will not save anything into the database, use a hidden field to check against computers sending spam, and configure flash messages to make the form look even better!

Installing Gems

First you will need to add mail_form and simple_form into your “Gemfile”.

gem 'mail_form'
gem 'simple_form'

Then you can run bundle install to install the gems.

Creating the Contact Form

First we will create the route: “config/routes.rb” Your route should look like this:

match '/contacts',     to: 'contacts#new',             via: 'get'
resources "contacts", only: [:new, :create]

Next you will need to make a controller: “app/controllers/contacts_controller.rb” Within the contacts controller it should look like this:

class ContactsController < ApplicationController
  def new
    @contact = Contact.new
  end

  def create
    @contact = Contact.new(params[:contact])
    @contact.request = request
    if @contact.deliver
      flash.now[:notice] = 'Thank you for your message. We will contact you soon!'
    else
      flash.now[:error] = 'Cannot send message.'
      render :new
    end
  end
end

Next we will need a model: “app/models/contact.rb” Inside the model it should look something like this:

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

Make sure to enter the what you want the subject of the message to be when it is sent to you. You also need to tell the mailer where you would like to send the messages to. Then we will need to create the views for the form. In “app/views/contacts/new.html.erb” you should put something like this:

<div align="center">
  <h3>Send A message to Us</h3>

  <%= 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 => true %>
    <div class= "hidden">
      <%= f.input :nickname, :hint => 'Leave this field blank!' %>
    </div>
    <div>
      </br>
      <%= f.button :submit, 'Send message', :class=> "btn btn-primary" %>
    </div>
  <% end %>
</div>


The send message button will be from twitter bootstrap. The nickname attribute will be hidden so that no one can fill it out but computers will fill it out. This will determine whether the message is coming from a computer or not.

Next we can add styling for the alert messages. In the file “app/views/contacts/create.html.erb” you should add this to put the alerts into flash messages.

<div>
  <% flash.each do |key, value| %>
    <div>
      <a href="#" data-dismiss="alert">×</a>
        <%= value %>
    </div>
  <% end %>
</div>

You will also need to add some styling in the style sheets. In “app/assets/stylesheets/custom.css.scss” you can add this to hide the nickname field we create earlier.

.hidden { display: none; }

In the same file you should add some styling for the flash notifications. I have set alert-error and alert-alert to be red to be used when things fail. I also have set alert-success and alert-notice to be green when things are successful.

/*flash*/

.alert-error {
background-color: #f2dede;
border-color: #eed3d7;
color: #b94a48;
text-align: left;
}

.alert-alert {
background-color: #f2dede;
border-color: #eed3d7;
color: #b94a48;
text-align: left;
}

.alert-success {
background-color: #dff0d8;
border-color: #d6e9c6;
color: #468847;
text-align: left;
}

.alert-notice {
background-color: #dff0d8;
border-color: #d6e9c6;
color: #468847;
text-align: left;
}

Now you have a working contact form. You can go to localhost:3000/contacts to see the form in action!

This tutorial was made using the following resources:

Tags: , , , , ,

29 responses to “Rails 4 Simple Form and Mail Form To Make Contact Form”

  1. tristelavoro says :

    Nice tutorial!
    Everything work correctly, and also on my dev environment it looks perfect.
    (on the terminal I see that my app send the mail).

    But at the end I do not receive any ‘real’ mail on my email account (set on gmail).

    For testing in the dev environment, and only there, I have to activate / deactivate some options somewhere?

      • bella says :

        I get the same problem of not receiving the email at the end and can’t get it to work.
        Anyone can explain more of the process?
        Thanks!

      • Tabi Slick says :

        Hi, I am having the same issue as tristelavoro. Would it be too much trouble to include the steps in this tutorial in order to receive real mail to the email address that we enter in our contacts model? Otherwise, this tutorial seems slightly incomplete.

      • Ohio Odion says :

        Thank you! both steps worked.
        But there was an issue here,
        ×
        but it was an easy fix

        but I already have a notice in my applicaation, so I’ll just take that out!
        Thanks again!

    • Sarah says :

      if your email address is a gmail account then firstly add these mailer settings to the config/environments/development.rb file:
      (Note: change user_name to your gmail address and change password to your gmail password)

      config.action_mailer.perform_caching = false
      config.action_mailer.perform_deliveries = true
      config.action_mailer.raise_delivery_errors = true

      config.action_mailer.delivery_method = :smtp
      config.action_mailer.smtp_settings = {
      address: ‘smtp.gmail.com’,
      port: 587,
      domain: ‘gmail.com’,
      user_name: ‘myemail@gmail.com’,
      password: ‘my_gmail_password’,
      authentication: ‘plain’,
      enable_starttls_auto: true }

      config.action_mailer.default_url_options = { :host => “localhost:3000” }

      Then you also need to turn on “less secure apps” in your gmail account to allow mails to be received from your application. See this link
      https://www.google.com/settings/security/lesssecureapps

  2. Jack says :

    What is the path to test? I tried localhost:3000/contacts and got a “No route matches [GET] “/contacts” ” error.

  3. Jack says :

    I went to localhost:3000/contacts/new and got this error:
    ============================================
    undefined method `new’ for Contact:Module

    Extracted source (around line #3):

    class ContactsController < ApplicationController
    def new
    @contact = Contact.new
    end

    def create

    • Daniel says :

      Sorry I forgot to include that! You can add this line to the routes ” match ‘/contacts’, to: ‘contacts#new’, via: ‘get’ ” You can view it by going to localhost:3000/contacts -I will edit the page and add it in!

      • Jack says :

        Thx, after doing that I get:
        ————————————————————

        undefined method `new’ for Contact:Module

        Extracted source (around line #3):

        class ContactsController < ApplicationController
        def new
        @contact = Contact.new
        end

        def create
        ————————————————————-

        I am too noob to figure this out on my own, what resources do you recommend for a C programmer to learn this?

  4. Daniel says :

    @Jack I am not sure what is wrong. Did you try restarting the local server? You should also check the names for the files and make sure they are plural where necessary.

    I would recommend this tutorial: http://ruby.railstutorial.org/ruby-on-rails-tutorial-book -Its one of the best resources and will help understand how rails works.

  5. Taylor Mitchell says :

    I am getting

    Errno::ECONNREFUSED: Connection refused – connect(2)
    from /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/net/smtp.rb:540:in `initialize’
    from /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/net/smtp.rb:540:in `open’
    from /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/net/smtp.rb:540:in `tcp_socket’
    from /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/net/smtp.rb:550:in `block in do_start’
    from /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/timeout.rb:66:in `timeout’
    from /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/net/smtp.rb:549:in `do_start’
    from /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/net/smtp.rb:519:in `start’
    from /Library/Ruby/Gems/2.0.0/gems/mail-2.5.4/lib/mail/network/delivery_methods/smtp.rb:112:in `deliver!’
    from /Library/Ruby/Gems/2.0.0/gems/mail-2.5.4/lib/mail/message.rb:2129:in `do_delivery’
    from /Library/Ruby/Gems/2.0.0/gems/mail-2.5.4/lib/mail/message.rb:232:in `block in deliver’
    from /Library/Ruby/Gems/2.0.0/gems/actionmailer-4.0.3/lib/action_mailer/base.rb:456:in `block in deliver_mail’
    from /Library/Ruby/Gems/2.0.0/gems/activesupport-4.0.3/lib/active_support/notifications.rb:159:in `block in instrument’
    from /Library/Ruby/Gems/2.0.0/gems/activesupport-4.0.3/lib/active_support/notifications/instrumenter.rb:20:in `instrument’
    from /Library/Ruby/Gems/2.0.0/gems/activesupport-4.0.3/lib/active_support/notifications.rb:159:in `instrument’
    from /Library/Ruby/Gems/2.0.0/gems/actionmailer-4.0.3/lib/action_mailer/base.rb:454:in `deliver_mail’
    from /Library/Ruby/Gems/2.0.0/gems/mail-2.5.4/lib/mail/message.rb:232:in `deliver’
    from /Library/Ruby/Gems/2.0.0/gems/mail_form-1.5.0/lib/mail_form/delivery.rb:151:in `deliver!’
    from /Library/Ruby/Gems/2.0.0/gems/activesupport-4.0.3/lib/active_support/callbacks.rb:386:in `_run__92463961908501673__deliver__callbacks’
    from /Library/Ruby/Gems/2.0.0/gems/activesupport-4.0.3/lib/active_support/callbacks.rb:80:in `run_callbacks’
    from /Library/Ruby/Gems/2.0.0/gems/mail_form-1.5.0/lib/mail_form/shim.rb:49:in `deliver’
    from (irb):3
    from /Library/Ruby/Gems/2.0.0/gems/railties-4.0.3/lib/rails/commands/console.rb:90:in `start’
    from /Library/Ruby/Gems/2.0.0/gems/railties-4.0.3/lib/rails/commands/console.rb:9:in `start’
    from /Library/Ruby/Gems/2.0.0/gems/railties-4.0.3/lib/rails/commands.rb:62:in `’
    from bin/rails:4:in `require’
    from bin/rails:4:in `’irb(main):004:0>

  6. Kyle Falconer says :

    I had the same problem as Jack. It ended up being a typo in one of the filenames. I was trying to use “contacts_conroller.rb” instead of “contacts_controller.rb”

  7. Aimee says :

    Any idea why I would be getting undefined method request= for Contact?

  8. Lloyd says :

    Hello! This post could not be written any better! Reading this post reminds me of my previous room mate! He always kept talking about this. I will forward this page to him. Pretty sure he will have a good read. Many thanks for sharing!

  9. 2nd says :

    If error `undefined method `contact_path’ for` add

    match ‘/contacts’, to: ‘contacts#new’, via: ‘get’, :as => :contact

  10. Mike says :

    How would I go about to make all of this work at URL ‘/contact’ (instead of ‘/contacts’)?

    I tried to change all the occurrences of the string “contacts” into “contact”, i.e.

    -3 times in ‘config/routes.rb’

    -moved app/controllers/contacts_controller.rb to app/controllers/contact_controller.rb and changed the first line therein to read “class ContactController < ApplicationController"

    -moved the views from 'app/views/contacts/ 'to 'app/views/contact/'

    but I end up with an error: "No route matches [POST] "/contacts""

  11. Faiq Adam says :

    I got error, i work well

    NoMethodError (undefined method `new’ for Contact:Module):
    app/controllers/contacts_controller.rb:3:in `new’

  12. My App says :

    I Added mandrillapp to my SMTP. Some time email not received

  13. hungmi says :

    Thanks a lot ! It works like a charm !
    Here is my route.rb for using localhost:3000/contact_us

    get ‘contact_us’ => ‘contacts#new’, as:”contact”

    resources ‘contacts’, only: [:create]

    Hope this helps.

  14. Tallkeith says :

    Greetings! This is a wonderful tutorial. It was very easy to follow and implement. However, I am receiving the following error in development:

    Net::SMTPAuthenticationError in ContactsController#create
    530-5.5.1 Authentication Required. Learn more at
    Extracted source (around line #9):
    7 @contact = Contact.new(params[:contact])
    8 @contact.request = request
    9 if @contact.deliver
    10 flash.now[:notice] = ‘Thank you for your message. We will contact you soon!’
    11 else
    12 flash.now[:error] = ‘Cannot send message.’

    app/controllers/contacts_controller.rb:9:in `create’

    Is this an issue with devise?
    I have checked my .env file, and everything there is correct. Please advise.

  15. kiran k s says :

    can’t receive real mail

  16. Jack says :

    This was an awesome post. Much appreciated.

  17. Jay Lane says :

    Thanks for a great tutorial for rails beginners if you can please help I am getting an end of file error on the contacts controller at if @contact.deliver:

    EOFError in ContactsController#create

    @contact = Contact.new(params[:contact])
    @contact.request = request
    if @contact.deliver
    flash.now[:notice] = ‘Thank you for your message. We will contact you soon!’
    else
    flash.now[:error] = ‘Cannot send message.’

    Odd thing is if I configure using actionmailer settings and hardcode the login info into my config file it works without issue but this is obviously a gigantic secops issue. Please help if you can.

  18. Shar says :

    Thanks for the awesome tut can you help troubleshooting though?

  19. Kai says :

    Hi, is it possible for you to do the testing for this as I am really stuck. Thanks in advance

Leave a comment