- Apr
- 02
- 2008
Custom Form Validations Without ActiveRecord
By: Chris Kaukis | Tags: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.
Share this post
Related Posts
You can leave a response, or trackback from your own site.


8 Responses to “Custom Form Validations Without ActiveRecord”
On April 4th, 2008 at 6:18 am A Fresh Cup » Blog Archive » Double Shot #180 said:
[...] Custom Forms Validation Without ActiveRecord - Using the validatable plugin. [...]
On April 7th, 2008 at 8:30 am Rails Podcast Brasil - Episódio 12 said:
[...] Custom Form Validations Without ActiveRecord [...]
On April 14th, 2008 at 5:48 am Thando Vuzane - Net Age said:
Hey, Thank you for the above. I was cracking my skull over it. You have relieved me from a lot of mind strain.
On April 16th, 2008 at 1:26 pm Jordan said:
This was perfect. Thanks.
On April 24th, 2008 at 2:11 pm Billy said:
While this looks like a promising gem, it lacks a lot of the more powerful ActiveRecord class methods, such as validate ! You cannot specify custom validations with this gem. You are constrained to the 6 or 8 validates_x methods it provides. Hopefully this will be fixed in the future.
On May 28th, 2008 at 10:27 am WN said:
Question from a RoR novice, Is it possible to have this as a plugin ?
On June 19th, 2008 at 2:41 pm Chad said:
Thanks for your contribution!
However, you should also look at a plugin called activerecord_base_without_table.
It allows you to define models that do not save into the database. I found this solution worked better for me because you end up with objects that are a little more compatible with the rest of the rails world. For example, I wanted to use the ‘human_attribute_override’ plugin for prettier error messages. This also solves Billy’s problem above where he wanted to write custom validations. And it’s a plugin rather than a gem, so it should make WN happy.
The plugin is remarkably short and sweet (only 26 lines long). However, sadly the author has not upgraded it to be compatible with rails 2. If you’re using rails 2, you need to edit one line: The call to readmethods on line 21 must be changed to generated_methods.
Good luck, and I hope this helps!
Here is the URL for the plugin:
http://agilewebdevelopment.com/plugins/activerecord_base_without_table
On July 31st, 2008 at 7:02 am Walter Lockhart said:
Re: 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.
Hi Chris,
I really enjoyed your post.
Would it be possible please to show how I would integrate these validations with a mailer and the respective views. I am developing a special inquiry form that requires a number of fields to be validated before the result of the form is emailed.
Thanks in advance.
Kind Regards
Walter