<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>RealityForge.org: Validations for non-ActiveRecord Model Objects</title>
    <link>/articles/2005/12/02/validations-for-non-activerecord-model-objects</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>A little short for a storm trooper</description>
    <item>
      <title>Validations for non-ActiveRecord Model Objects</title>
      <description>&lt;p&gt;Rails provides support for validating form input if the form is backed by an ActiveRecord. The application I am currently working on has a form that has a large number of input parameters but is not persisted to the database. I still wanted to use the ActiveRecord &lt;a href="http://api.rubyonrails.com/classes/ActiveRecord/Validations.html"&gt;Validations&lt;/a&gt; as they make my life easier but I did not know if there was an simple way to do this.&lt;/p&gt;


	&lt;p&gt;Initially I created a dummy table in the database with just an id field and made my model object sub-class ActiveRecord. I could then use the validations with all the fields I had defined using &lt;code&gt;attr_accessor&lt;/code&gt;. This looked something like;&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Search&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Base&lt;/span&gt;

  &lt;span class="ident"&gt;attr_accessor&lt;/span&gt; &lt;span class="symbol"&gt;:user_name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:email&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:locator&lt;/span&gt;

  &lt;span class="ident"&gt;validates_length_of&lt;/span&gt; &lt;span class="symbol"&gt;:user_name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; 
                      &lt;span class="symbol"&gt;:within&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="number"&gt;6&lt;/span&gt;&lt;span class="punct"&gt;..&lt;/span&gt;&lt;span class="number"&gt;20&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; 
 &lt;span class="symbol"&gt;:too_long&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;pick a shorter name&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; 
                      &lt;span class="symbol"&gt;:too_short&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;pick a longer name&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="ident"&gt;validates_format_of&lt;/span&gt; &lt;span class="symbol"&gt;:email&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; 
                     &lt;span class="symbol"&gt;:with&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;^([^@&lt;span class="escape"&gt;\s&lt;/span&gt;]+)@((?:[-a-z0-9]+&lt;span class="escape"&gt;\.&lt;/span&gt;)+[a-z]{2,})$&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;i&lt;/span&gt;
  &lt;span class="ident"&gt;validates_numericality_of&lt;/span&gt; &lt;span class="symbol"&gt;:locator&lt;/span&gt;
  &lt;span class="punct"&gt;...&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;In my controller I created the Search object in the same way that I created all the other model objects but I never called save. Instead I called the &lt;code&gt;valid?&lt;/code&gt; method to check whether the model passed all the validations. If the model is not valid the &lt;code&gt;@search.errors&lt;/code&gt; object is populated with all the errors.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;NavigatorController&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;ApplicationController&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;search&lt;/span&gt;
    &lt;span class="attribute"&gt;@search&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Search&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:search&lt;/span&gt;&lt;span class="punct"&gt;])&lt;/span&gt;
    &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="attribute"&gt;@search&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;valid?&lt;/span&gt;
    &lt;span class="punct"&gt;...&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="punct"&gt;...&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Of course this left a bad taste in my mouth as it is a seriously ugly hack that requires an empty table in the database just to get form validation working. So I began to look at what I needed to do to implement an &lt;b&gt;ActiveForm&lt;/b&gt; object. I was not looking forward to this task as I had read on the rails mailing list that the Validations were intermingled with ActiveRecord::Base and difficult to untangle.&lt;/p&gt;


	&lt;p&gt;This could not be further from the truth. The first thing I did was create a new ActiveForm class and &lt;code&gt;include ActiveRecord::Validations&lt;/code&gt;. This caused a few errors as the ActiveRecord::Validations class attempts to call alias_method for methods that do not exist in ActiveForm. I implement these methods (save and update_attribute) so that they raise a NotImplementedError exception. Then I attempt to call the &lt;code&gt;valid?&lt;/code&gt; method but it calls the &lt;code&gt;new_record?&lt;/code&gt; method which I implement to return true. To view the errors in the view using the standard helper methods I need to implement the human_attribute_name method. These changes seem to get basic validations working.&lt;/p&gt;


	&lt;p&gt;The only validations that are not working are &lt;code&gt;validates_uniqueness_of&lt;/code&gt; and &lt;code&gt;validates_numericality_of&lt;/code&gt;. &lt;code&gt;validates_uniqueness_of&lt;/code&gt; is not expected to work as it accesses the database so I just make it raise a NotImplementedError exception. &lt;code&gt;validates_numericality_of&lt;/code&gt;
 does not work as it relies on a method named &amp;#8221;#{attr_name}_before_type_cast&amp;#8221; for each attribute named &amp;#8220;attr_name&amp;#8221;. This is an artifact of the type coercion that ActiveRecord performs on input parameters. ActiveRecord will convert an input parameter from a string to an integer if the underlying database record stores the field as an integer. As this does not occur with ActiveForm I just duplicated the method and replaced &amp;#8221;#{attr_name}_before_type_cast&amp;#8221; with &amp;#8221;#{attr_name}&amp;#8221;.&lt;/p&gt;


	&lt;p&gt;The only functionality that ActiveForm was missing was the ability to create a model object from a hash. As ActiveForm does not need to do any type coercion this is as simple as&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;attributes&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;nil&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
   &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;attributes&lt;/span&gt;
      &lt;span class="ident"&gt;attributes&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;key&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="ident"&gt;value&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
        &lt;span class="ident"&gt;send&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;key&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;=&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="ident"&gt;value&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
      &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="keyword"&gt;yield&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt; &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;block_given?&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;At this stage ActiveForm is in a usable state and it took less than 20 minutes. It only took that long because I needed to restart webrick for each change (not to mention the fact that I had never looked at ActiveRecord before). Isn&amp;#8217;t ruby/rails great?&lt;/p&gt;


	&lt;p&gt;To get this working grab the &lt;a href="/files/active_form.rb"&gt;active_form.rb&lt;/a&gt; file and place it in the app/models directory. You can then make your model objects extend ActiveForm and use them like regular ActiveRecord objects.&lt;/p&gt;


	&lt;p&gt;I cleaned up a few warts of ActiveForm like overriding methods you should not be calling (save!, save_with_validation, create!, validate_on_create, validate_on_update). I hope to get motivated enough to send a patch that enables this style of functionality in the core once edge rails is working for me again.&lt;/p&gt;


	&lt;p&gt;&lt;b&gt;Update:&lt;/b&gt;&lt;/p&gt;


	&lt;p&gt;It seems there is already a &lt;a href="http://wiki.rubyonrails.com/rails/pages/HowToUseValidationsWithoutExtendingActiveRecord"&gt;HowTo&lt;/a&gt; on the rails wiki that describes a similar technique. However rather than duplicating &lt;code&gt;validates_numericality_of&lt;/code&gt; they handle the calls to &amp;#8221;#{attr_name}_before_type_cast&amp;#8221; by implementing a &lt;a href="http://www.rubycentral.com/ref/ref_c_object.html#method_missing"&gt;method_missing&lt;/a&gt; method which I incorporated to cleanup my code.&lt;/p&gt;


	&lt;p&gt;&lt;b&gt;Update on 12th Dec 2005&lt;/b&gt;&lt;/p&gt;


	&lt;p&gt;Today I decided that I needed to add reloading of ActiveForm subclasses and this is done with the following code chunk.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;dispatcher&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Dispatcher&lt;/span&gt;
  &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;
    &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="punct"&gt;!&lt;/span&gt; &lt;span class="ident"&gt;method_defined?&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:form_original_reset_application!&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; 
      &lt;span class="keyword"&gt;alias&lt;/span&gt; &lt;span class="symbol"&gt;:form_original_reset_application!&lt;/span&gt; &lt;span class="symbol"&gt;:reset_application!&lt;/span&gt;
      &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;reset_application!&lt;/span&gt;
        &lt;span class="ident"&gt;form_original_reset_application!&lt;/span&gt;
        &lt;span class="constant"&gt;Dependencies&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;remove_subclasses_for&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;ActiveForm&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="keyword"&gt;defined?&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;ActiveForm&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
      &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;&lt;b&gt;Download:&lt;/b&gt; &lt;a href="/files/active_form.rb"&gt;active_form.rb&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;&lt;b&gt;Update on 1st March 2006&lt;/b&gt;&lt;/p&gt;


	&lt;p&gt;Available as a plugin at&lt;/p&gt;


	&lt;p&gt;svn: &lt;a href="http://www.realityforge.org/svn/code/active-form/trunk"&gt;http://www.realityforge.org/svn/code/active-form/trunk&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Fri, 02 Dec 2005 22:48:00 +1100</pubDate>
      <guid isPermaLink="false">urn:uuid:ab47f804c7ed2a38c4c29d82f56c5548</guid>
      <author>Peter Donald</author>
      <link>http://www.realityforge.org/articles/2005/12/02/validations-for-non-activerecord-model-objects</link>
      <category>Rails</category>
      <enclosure type="application/octet-stream" url="http://www.realityforge.org/files/active_form.rb" length="1894"/>
      <trackback:ping>http://www.realityforge.org/articles/trackback/9</trackback:ping>
    </item>
    <item>
      <title>"Validations for non-ActiveRecord Model Objects" by Peter</title>
      <description>&lt;p&gt;There is also an article &lt;a href="http://rails.techno-weenie.net/tip/2005/11/19/validate_your_forms_with_a_table_less_model" rel="nofollow"&gt;Validate your forms with a table-less model&lt;/a&gt; by Rick Olson that may be useful&lt;/p&gt;</description>
      <pubDate>Tue, 06 Dec 2005 12:36:16 +1100</pubDate>
      <guid isPermaLink="false">urn:uuid:c31fb5ce-a33a-42db-ac70-0184df38055b</guid>
      <link>http://www.realityforge.org/articles/2005/12/02/validations-for-non-activerecord-model-objects#comment-17</link>
    </item>
    <item>
      <title>"Validations for non-ActiveRecord Model Objects" by Peter</title>
      <description>&lt;p&gt;I went to create a wiki page on this and found that there is already a &lt;a href="http://wiki.rubyonrails.com/rails/pages/HowToUseValidationsWithoutExtendingActiveRecord" rel="nofollow"&gt;HowTo&lt;/a&gt; so I may just update that page with some more details.&lt;/p&gt;</description>
      <pubDate>Tue, 06 Dec 2005 11:12:20 +1100</pubDate>
      <guid isPermaLink="false">urn:uuid:0dc10f7e-b46c-43b0-9d54-6eff77fb63d3</guid>
      <link>http://www.realityforge.org/articles/2005/12/02/validations-for-non-activerecord-model-objects#comment-16</link>
    </item>
    <item>
      <title>"Validations for non-ActiveRecord Model Objects" by Martin</title>
      <description>&lt;p&gt;Followed your link from the Ruby on Rails mailing list digest. You shoud add a link to your code on the rubyonrails wiki if you haven&amp;#8217;t done so already. Very handy &amp;#8211; thanks Peter!&lt;/p&gt;</description>
      <pubDate>Sun, 04 Dec 2005 03:20:03 +1100</pubDate>
      <guid isPermaLink="false">urn:uuid:210b00c4-680b-447f-a4d0-f1005ca34de5</guid>
      <link>http://www.realityforge.org/articles/2005/12/02/validations-for-non-activerecord-model-objects#comment-13</link>
    </item>
  </channel>
</rss>
