Have you ever wanted to create a form with the nice ActiveRecord Validations, but not use a database or ActiveRecord model? Like if you wanted to just have the result of the form emailed. An example might be a contact form or a special inquiry form that requires a name, an email, and perhaps a phone number.
Well, you can, and it”s quite easy too. Especially with the help of a little gem called Validatable.
To install:
sudo gem install validatable
There are at least 2 ways to include this in your Rails project, I’m going to cheat and use the shortcut method of including it in the environment.rb file to save on time and typing (and your patience):
Add to your environment.rb file:
require "validatable"
Next, lets create a new class file called contact.rb. You can put this in lib, models, or some other place, it”s up to you. I put it in my models directory for this example.
The contents of contact.rb will look like the following:
class Contact include Validatable attr_accessor :name, :email, :phone, :message validates_presence_of :name, :message => "Name is required." validates_format_of :email, :with => /^[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,4}$/i, :message => "Email is not valid." validates_format_of :phone, :with => /^[0-9]{3,3}-[0-9]{3,3}-[0-9]{4,4}$/, :message => "Phone number is not valid (xxx-xxx-xxxx)." def phone=(phone) @phone = phone.gsub(/[^0-9]/, "").gsub(/^([0-9]{0,3})([0-9]{0,3})([0-9]{0,})$/) do |match| tmp = "" tmp += $1 if $1.size > 0 tmp += "-" + $2 if $2.size > 0 tmp += "-" + $3 if $3.size > 0 tmp end end def deliver if valid? Notification.deliver_contact(self) else false end end end
Oh my, doesn”t that look familiar? It looks just like an ActiveRecord model, except, gasp! It doesn”t inherit from ActiveRecord::Base. It”s just a plain Ruby class. Spiffy!
I”m assuming everything else looks familiar to you, yes? Swell, moving on then.
You will also notice I have a Notification mailer in there.
Note: I”m assuming you also know how to set up a mailer and the respective views. If you do not, comment below and I will add those pieces to this post if you desire.
Try it out, open up your console and play around.
>> c = Contact.new => #<Contact:0x218e974> >> c.name = "Chris" => "Chris" >> c.valid? => false >> c.errors.full_messages => ["Email Email is not valid.", "Phone Phone number is not valid (xxx-xxx-xxxx)."] >> c.email = "chris@techcfl.com" => "chris@techcfl.com" >> c.phone = "1234567890" => "1234567890" >> c.valid? => true >> c.name => "Chris" >> c.email => "chris@techcfl.com" >> c.phone => "123-456-7890" >> c.message = "Stillwater? Wtf is that?" => "Stillwater? Wtf is that?"
Cool! Now let”s put this into Rails context and see how to use it for handling validations in our controller and view.
In the controller where you want to handle your contact form, you might have something like the following:
def contact @contact = Contact.new if request.post? @contact.name = params[:name] @contact.email = params[:email] @contact.phone = params[:phone] @contact.ticker = params[:ticker] if @contact.valid? @contact.deliver flash[:notice] = "Thank you for you interest." redirect_to root_url end end end
Here is an example view with custom error handling:
<% form_tag contact_path do %> <table> <tr> <td> <label for="name">Name:</label> </td> <td> <%= text_field_tag "name", @contact.name %> <%= error_messages_for_attribute(@contact, :name) %> </td> </tr> <tr> <td> <label for="email">Email:</label> </td> <td> <%= text_field_tag "email", @contact.email %> <%= error_messages_for_attribute(@contact, :email) %> </td> </tr> <tr> <td> <label for="phone">Phone:</label> </td> <td> <%= text_field_tag "phone", @contact.phone %> <%= error_messages_for_attribute(@contact, :phone) %> </td> </tr> <tr> <td> <label for="message">Message:</label> </td> <td> <%= text_area_tag "message", @contact.message %> <%= error_messages_for_attribute(@contact, :message) %> </td> </tr> <tr> <td colspan="2"> <%= submit_tag "Submit" %> </td> </tr> </table> <% end %>
You will notice a custom error_messages_for_attribute helper method I created, here is the code I used for that:
def error_messages_for_attribute(object, attribute) if object.errors.on(attribute) html = '<small class="errors"><ul>' object.errors.on(attribute).each do |message| html += "<li>" + message + "</li>" end html += "</ul></small>" end end
I hope you found this useful.
Other Posts That Might Interest You

