Rails 2.0: Validations Without Extending ActiveRecord::Base

In more “enterprisey” web stacks (such as Java with Hibernate and Spring MVC), it’s straightforward to design a validatable form whose contents do not correspond directly — if at all — to a persistent OR/M class: such as may happen in an ecommerce site where you’re collecting payment information but can only store some of it in the database for legal reasons. Just create a MVC-level view object using your framework-specific validation mechanism, and translate to/from the relevant OR/M classes as necessary in the controller.

This scenario isn’t always straightforward to handle in Rails since the stack layers are smooshed together. In Rails 1.2.x, you could use (some) validations in your non-persistent PORO objects by extending ActiveRecord::Base and overriding the initializer to skip the databases-related stuff. Alas, this hack does not seem to work in Rails 2.0, but I have a solution which, in my brief testing, seems to work better than the aforementioned Rails 1.2 hack.

Here’s how I used ActiveRecord::Validations in one of my view-only classes in a Rails 2.0.2 application without needing a dummy table in the database or ActiveRecord::Base.


require 'active_record/validations'

class Card

# Define your arbitrary PORO attributes.
attr_accessor :number
attr_accessor :expiration_month
attr_accessor :expiration_year
attr_accessor :verification_value

# For the ActiveRecord::Errors object.
attr_accessor :errors

def initialize(opts = {})

# Create an Errors object, which is required by validations and to use some view methods.
@errors = ActiveRecord::Errors.new(self)

end

# Dummy stub to make validtions happy.
def save
end

# Dummy stub to make validtions happy.
def save!
end

# Dummy stub to make validtions happy.
def new_record?

false

end

# Dummy stub to make validtions happy.
def update_attribute
end

# Mix in that validation goodness!
include ActiveRecord::Validations

# Use validations.
validates_presence_of :number
validates_presence_of :expiration_month
validates_presence_of :expiration_year
validates_presence_of :verification_value

end

8 thoughts on “Rails 2.0: Validations Without Extending ActiveRecord::Base”

  1. What about just marking the class as abstract?

    class Car < ActiveRecord::Base
    self.abstract = true
    end

  2. I had a lot of problems with this on Rails 2.2.2, in the end after trying to make this hack work-it was a lot easier to go with the validator gem (http://validatable.rubyforge.org/). It works almost identically to the built in model validation. After validation, errors are loaded into the errors attribute and can be handled in the view. No auto helpers built in, but this blog got me started : http://rorblog.techcfl.com/2008/04/02/custom-form-validations-without-activerecord/

    Hopefully this saves someone else some time.

    Ben

  3. Thanks for the note, Ben. This was written with 1.2 in mind, and I don’t think I’ve tested this approach post ~2.0. I’ll definitely have to check out that gem in the future!

Leave a Reply

Your email address will not be published. Required fields are marked *