ActiveForm

From WhyNotWiki

Jump to: navigation, search
Homepage: http://www.realityforge.org/articles/2005/12/02/validations-for-non-activerecord-model-objects
Documentation: Readme
Source code: http://www.realityforge.org/svn/code/active-form/trunk/

meat



Description: Validation at the form/controller level. Makes it easy to have model objects that support the ActiveRecord Validations but are not backed by database tables.





Contents

[edit] [Caveats (category)]

[edit] ActiveForm does not do type-casting, so everything will remain a string!

[edit]

I don't fully understand why it's necessary but the whatever_before_type_cast methods are implemented via method_missing...

http://www.realityforge.org/svn/code/active-form/trunk/lib/active_form.rb

  def method_missing( method_id, *args )
    if md = /_before_type_cast$/.match(method_id.to_s)
      attr_name = md.pre_match
      return self[attr_name] if self.respond_to?(attr_name)
    end
    super
  end

[edit] Why doesn't it do type-casting?

It doesn't do typecasting probably because it has no way of knowing what type each "column" should be. In the case of ActiveRecord, of course, it would reflect from the table's schema in the database and would know which fields had been defined as integers, etc. But in the case of ActiveForm, there is no associated database table to reflect against!

[edit] When is this a concern?

When you use a validation macro that expects columns to have been type-cast into integers...

For instance,

class Form < ActiveForm
  attr_accessor :price
  validates_inclusion_of :price, :in => 1..1000
end

If the input comes in from a form, then nothing you enter will satisfy this validation! Why? Because everything you enter will be a string. And even if the string you entered is within the range -- for example, "50" -- it will still fail the validation because (1..1000).include?("50") is false!

irb -> (1..1000).include?("50")
    => false

irb -> (1..1000).include?(50)
    => true

[edit] Work around for decimal/currency types

Workaround:

# In your model:
  before_validation :type_cast
  def type_cast
    self.price = self.price.to_f.round_to(0.01) if price
  end

It's kind of ugly (not very "semantic"), but it works...


[edit] Installation

svn externalize http://www.realityforge.org/svn/code/active-form/trunk/ vendor/plugins/active-form
Facts about ActiveFormRDF feed
Description [Oops! No type defined for attribute]
Personal tools