ActiveForm
From WhyNotWiki
| 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/
|
| 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
