<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Simone Carletti&#039;s Blog &#187; activerecord</title>
	<atom:link href="http://www.simonecarletti.com/blog/tags/activerecord/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.simonecarletti.com/blog</link>
	<description>Simone Carletti&#039;s personal ramblings on programming, syndication, search engines &#38; marketing.</description>
	<lastBuildDate>Tue, 07 Feb 2012 08:48:33 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>The Road to Rails 3: make your Rails 2.3 project more Rails 3 oriented</title>
		<link>http://www.simonecarletti.com/blog/2010/07/the-way-to-rails-3/</link>
		<comments>http://www.simonecarletti.com/blog/2010/07/the-way-to-rails-3/#comments</comments>
		<pubDate>Mon, 26 Jul 2010 14:12:21 +0000</pubDate>
		<dc:creator>Simone Carletti</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[activerecord]]></category>
		<category><![CDATA[bunder]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[rails 3]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.simonecarletti.com/blog/?p=1131</guid>
		<description><![CDATA[The goal of this article is to feature a list of tips and changes you can already introduce in your Rails 2 application to anticipate the migration and make your code more compatible with Rails 3.]]></description>
			<content:encoded><![CDATA[<p><strong>Update 2010-08-10:</strong> added <code>ActiveRecord::Base#add_to_base</code> section</p>
<p>With the first Rails 3 Release Candidate <a href="http://twitter.com/spastorino/status/19459068259">available in a few days</a> and the final version just around the corner, it&#8217;s time to start thinking in <em>The Rails 3 way</em>. Many developers, including myself, already started to work with Rails 3 and many others are tracking the changes, waiting for the right time to <strong>upgrade their Rails 2 applications</strong>.</p>
<p>There are already thousands of articles talking about the most cool Rails 3 features so I will skip that part in this article. After all, I already introduced a couple of <a title="rails 3  –  Simone Carletti's Blog" href="http://www.simonecarletti.com/blog/tags/rails-3/">Rails 3 libraries</a>. I&#8217;d like this article to be something different, embracing a more practical style.</p>
<p>I have been working with Rails 3 since the first beta version and all my Rails applications, <a title="RoboDomain" href="http://www.robodomain.com/">except one</a>, are now running Rails 3 with Ruby 1.8.7 or <a href="http://twitter.com/weppos/status/19326340657">Ruby 1.9.2</a>. Trust me, <strong>upgrading an application to Rails 3 can be a real hassle</strong> if you don&#8217;t follow the right way, especially for complex applications.</p>
<p>The goal of this article is to <strong>feature a list of tips and changes you can already introduce in your Rails 2 application to anticipate the migration</strong> and make your code more compatible with Rails 3. The more steps you follow, the less problems you are likely to encounter when upgrading the codebase to Rails 3.</p>
<p>Kudos to <a title="Rails 3 : Anticipating migration for 2.3 beginners - Stack Overflow" href="http://stackoverflow.com/questions/2190848/rails-3-anticipating-migration-for-2-3-beginners/2191284">this StackOverflow question</a> for inspiring me this post.<span id="more-1131"></span><br />
<div class="flash-message with-icon featured clearfix">
<a href="http://thinkcode.tv/catalog/upgrading-rails-3/?utm_source=simonecarletti.com&utm_medium=link&utm_content=message-rails3upgrade&utm_campaign=rails3upgrade"><img src="http://www.simonecarletti.com/images/screencasts/rails3-small.png" height="100" class="alignleft" /></a>
<h4>Upgrading to Rails 3 screencast</h4>
<p>Looking for a Rails 3 screencast? <a href="http://thinkcode.tv/catalog/upgrading-rails-3/?utm_source=simonecarletti.com&utm_medium=link&utm_content=message-rails3upgrade&utm_campaign=rails3upgrade">This one hour screencast is a live example of upgrading a real-world application from Rails 2 to Rails 3.</a></p>
</div></p>
<h2>Prerequisites</h2>
<p>This section includes some highly recommended prerequisites your application and environment should meet if you want to take the way to Rails 3. If you care about your happiness, don&#8217;t try to upgrade to Rails 3 unless all the prerequisites are satisfied.</p>
<h3>Tests</h3>
<p>I will repeat it until the end of the world: don&#8217;t try to work with Ruby or Rails without using unit, functional and integration tests. You have several different choices: <code>Test::Unit</code>, <code>Shoulda</code>, <code>Cucumber</code>, <code>RSpec</code>&#8230; pick one and <strong>create your test suites as long as you add features or fix bugs</strong>.</p>
<p><strong>Don&#8217;t try to upgrade to Rails 3 unless you have a reasonable code coverage</strong>. And this is not because tests are cool or make you feel cool, but because Rails 3 changes so many aspects of your Rails application that upgrading without using your tests will be really painful.</p>
<p>Also, be sure to test your view helpers. Rails 3 adds string escaping by default and many of your Rails helpers might require a fix.</p>
<h3>Ruby 1.8.7 or 1.9.2</h3>
<p><strong>Rails 3 no longer works with Ruby 1.8.6</strong>. You might also want interested to know that Ruby 1.9.1 is <a href="https://rails.lighthouseapp.com/projects/8994/tickets/4823-rails-3-beta4-activesupport-error#ticket-4823-3">not officially supported</a> and <strong>Ruby 1.9.2</strong> is the first (and the only) choice if you want to take advantage of Ruby 1.9 features.</p>
<p>Don&#8217;t fall into the trap: Ruby 1.9.1 seem work at a first glance, as long as you don&#8217;t use some incompatible features such as the <code>#truncate</code> helper, which relies on <code>ActiveSupport::Multibyte::Chars</code>, which doesn&#8217;t play very nice with Ruby 1.9.1.</p>
<h2>Mandatory Changes</h2>
<p>This section includes incompatible changes in the Rails 3 codebase, new features or deprecated behaviors you should avoid to facilitate the upgrade to Rails 3. I call this section &#8220;mandatory&#8221; because, skipping one of these tasks might prevent your Rails 3 application from loading or running properly.</p>
<h3>Use Bundler to manage your Gem dependencies</h3>
<p>Unless you lived in a cave for the last year, you probably heard about <a title="Bundler: The best way to manage Ruby applications" href="http://gembundler.com/">Bundler</a>. <strong>Bundler is the new way to manage Gem dependencies</strong> in Rails 3 applications. Bundler is also quickly becoming the new Ruby standard to package and require external Gems in a Ruby project.</p>
<p>What you might not know, is that you can <strong>start using Bundler with Rails 2.3 right now</strong>. Just follow <a title="Bundler: The best way to manage Ruby applications" href="http://gembundler.com/rails23.html">these steps</a> to override the Rails 2.3 gem handling and replace it with support for Bundler.</p>
<p>The <a title="Bundler: The best way to manage Ruby applications" href="http://gembundler.com/">Bundler website</a> contains all the information you need to know about Bundler and the Gemfile specification file.</p>
<h3>Unobtrusive JavaScript</h3>
<p><a title="Understanding the Unobtrusive JavaScript technique  –  Simone Carletti's Blog" href="http://www.simonecarletti.com/blog/2010/06/unobtrusive-javascript-technique/">Unobtrusive JavaScript</a> is one of the biggest changes on the frontend side of the upcoming Rails 3 version.</p>
<p>Rails 3 is no longer Prototype-oriented, Rails 3 code is now JavaScript framework agnostic and there are many incompatible changes that require your attention. Learn more about <a title="Unobtrusive JavaScript in Rails 3  –  Simone Carletti's Blog" href="http://www.simonecarletti.com/blog/2010/06/unobtrusive-javascript-in-rails-3/">Unobtrusive JavaScript in Rails 3</a>.</p>
<p><strong>Start converting your JavaScript </strong><strong>right now</strong> and avoid using deprecated helper so that you won&#8217;t have to change all your code later when switching to Rails 3.</p>
<h3><code>Object#returning</code></h3>
<p>Did you know that <code>Object#returning</code> has been <a title="Commit b0b9bf320409b66c6c6b680371aca590297cd4cc to rails's rails - GitHub" href="http://bit.ly/9goQdm">removed in Rails 3</a>? Replace your code with <a title="Commit b1cfcedc8f6dde3b0855fc8fd564e72e730ba5cf to rails's rails - GitHub" href="http://bit.ly/cBA5eM"><code>Object#tap</code></a> as soon as possible.</p>
<h3>Beware of HTML code in YAML locale files</h3>
<p>Do you use HTML in your YAML locale files? Make sure the key ends with _html or <a title="Commit 5208cc3cf5d54720512ff50c2b97e9f4369aaa27 to rails's rails - GitHub" href="http://github.com/rails/rails/commit/5208cc3cf5d54720512ff50c2b97e9f4369aaa27">Rails 3 will escape it</a>.</p>
<h3>Rails Metal has been removed</h3>
<p>Since Rails 3 is closer to Rack, the Metal abstraction is no longer needed. The Rails Metal feature has been removed from Rails 3.<br />
You can read the <a title="Commit ed34652d1aca148fea61c5309c1bd5ff3a55abfa to rails's rails - GitHub" href="http://github.com/rails/rails/commit/ed34652d1aca148fea61c5309c1bd5ff3a55abfa">commit message</a> to have an explanation of what to do with your existing Metals.</p>
<h3>Only ActiveRecord fixtures in the <code>test/fixtures</code> folder</h3>
<p>Commit <a title="Commit 8ec085bf1804770a547894967fcdee24087fda87 to rails's rails - GitHub" href="http://github.com/rails/rails/commit/8ec085bf1804770a547894967fcdee24087fda87">8ec085bf1804770a547894967fcdee24087fda87</a> breaks the usage of the fixtures folder for non-model fixtures. If you were used to place fixture files for your custom libraries in the <code>test/fixtures</code> directory, move them to an other folder (e.g. <code>test/files</code>).</p>
<h3>Rails <code>error_messages_for</code>, <code>error_message_on</code>, &#8230; helpers</h3>
<p>Commit <a title="Commit cd79a4617421f1b66e905f5da84ff28004e2bedd to rails's rails - GitHub" href="http://github.com/rails/rails/commit/cd79a4617421f1b66e905f5da84ff28004e2bedd">cd79a4617421f1b66e905f5da84ff28004e2bedd</a> removes <code>input</code>, <code>form</code>, <code>error_messages_for</code> and <code>error_message_on</code> from the framework. The helpers are still available in a plugin called <a title="rails's dynamic_form at master - GitHub" href="http://github.com/rails/dynamic_form">dynamic_form</a>, but I strongly encourage you to update your code in order to avoid using the plugin. Ryan Bates <a title="Railscasts - Validations in Rails 3" href="http://railscasts.com/episodes/211-validations-in-rails-3">demonstrates</a> a possible approach.</p>
<h2>Optional Changes</h2>
<p>This section includes changes for which Rails 3 provides a deprecation warning or fallback. For this reason, you are not forced to complete all these tasks before upgrading to Rails 3. However, I strongly suggest you to review all the steps and change the code before upgrading to Rails 3 to reduce the number of warnings in your console and log file.</p>
<h3><code>RAILS_ROOT</code>, <code>RAILS_ENV</code>, and <code>RAILS_DEFAULT_LOGGER</code> constants are now deprecated</h3>
<p>Railties, one of the Gems part of the Rails 3 framework, now deprecates the following global constants:</p>
<ul>
<li><code>RAILS_ROOT</code> in favour of <code>Rails.root</code></li>
<li><code>RAILS_ENV</code> in favour of <code>Rails.env</code></li>
<li><code>RAILS_DEFAULT_LOGGER</code> in favour of <code>Rails.logger</code></li>
</ul>
<p><a title="litany against fear ¤ by nick quaranto ¤ The Rails Module (in Rails 3)" href="http://litanyagainstfear.com/blog/2010/02/03/the-rails-module/">Learn more</a>.</p>
<h3>Avoid legacy <code>ActiveRecord::Base#find([:all | :first | :last])</code> statements</h3>
<p>You might have heard about the changes in the <a href="http://m.onkey.org/2010/1/22/active-record-query-interface">Active Record query interface for Rails 3</a>. Here&#8217;s an interesting quote.</p>
<blockquote><p>Currently ActiveRecord provides the following finder methods:</p>
<ul>
<li><code>find(id_or_array_of_ids, options)</code></li>
<li><code>find(:first, options)</code></li>
<li><code>find(:all, options)</code></li>
<li><code>first(options)</code></li>
<li><code>all(options)</code></li>
<li><code>update_all(updates, conditions, options)</code></li>
</ul>
<p>and the following calculation methods:</p>
<ul>
<li><code>count(column, options)</code></li>
<li><code>average(column, options)</code></li>
<li><code>minimum(column, options)</code></li>
<li><code>maximum(column, options)</code></li>
<li><code>sum(column, options)</code></li>
<li><code>calculate(operation, column, options)</code></li>
</ul>
<p>Starting with Rails 3, supplying any option to the methods above will be deprecated. Support for supplying options will be removed from Rails 3.2. Moreover, <code>find(:first)</code> and <code>find(:all)</code> (without any options) are also being deprecated in favour of first and all.</p></blockquote>
<p>If you have any code using the legacy <code>#find(:all)</code>, <code>#find(:first)</code> or <code>#find(:last)</code> methods, start converting them now into the corresponding <code>#all</code>, <code>#first</code>, and <code>#last</code> alternatives. You can pass the options to the method or use anonymous/named scopes.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"># deprecated statement<br />
Post.find(:all, :conditions =&gt; { :approved =&gt; true })<br />
<br />
# better version<br />
Post.all(:conditions =&gt; { :approved =&gt; true })<br />
<br />
# best version (1)<br />
named_scope :approved, :conditions =&gt; { :approved =&gt; true }<br />
Post.approved.all<br />
<br />
# best version (2)<br />
Post.scoped(:conditions =&gt; { :approved =&gt; true }).all</div></td></tr></tbody></table></div>
<h3>Simulating the new Active Record API</h3>
<p>ActiveRecord in Rails 3 will expose a <a href="http://m.onkey.org/2010/1/22/active-record-query-interface">brand new API</a>. You can try to use a very similar approach in Rails 2.3 using <code>named_scope</code>s.</p>
<p>For instance, here&#8217;s a few <code>named_scope</code>s which simulates Rails 3 features.</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">named_scope :limit, lambda { |limit| { :limit =&gt; limit } }<br />
named_scope :select, lambda { |select| { :select =&gt; select } }<br />
named_scope :where, lambda { |conditions| { :conditions =&gt; conditions } }</div></td></tr></tbody></table></div>
<p>You can create a shared module with all the corresponding Rails 3 new methods implemented in Rails 2 and start using the new syntax as soon as possible. Once switched to Rails 3, simply remove the module inclusion to have your code ready for ActiveRecord 3.</p>
<p><strong>Update 2010-07-26:</strong> <a href="http://ruby5.envylabs.com/episodes/99-episode-97-july-27-2010">thanks to Ruby5</a> I just discovered that someone already created a library to simulate Rails 3 API, called <a href="http://github.com/gammons/fake_arel">fake_arel</a>.</p>
<h3>Rails XSS protection</h3>
<p>In order to protect the application from XSS attacks, <a title="Rails Dispatch | Presented by Engine Yard" href="http://www.railsdispatch.com/posts/security"><strong>Rails 3 will automatically escape any content</strong></a><strong> that does not originate from inside of Rails itself</strong>. This is a very important, non compatible, change which may seriously break your application and the existing view helpers.</p>
<p>Fortunately, you can already experiment the default escaping with Rails 2.3 thanks to the <a title="rails's rails_xss at master - GitHub" href="http://github.com/rails/rails_xss">rails_xss plugin</a>. This plugin replaces the default ERB template handlers with erubis, and switches the behaviour to escape by default rather than requiring you to escape. This is consistent with the behaviour in Rails 3.0.</p>
<p>You are encouraged to try it as soon as possible.</p>
<h3>Plugin tasks and initialization</h3>
<p>Rake tasks in <code>vendor/plugins/PLUGIN/tasks</code> are deprecated, as well the <code>vendor/plugin/PLUGIN/rails/init.rb</code> file. <a title="Rails 3 Plugins - Part 1 - The Big Picture" href="http://www.themodestrubyist.com/2010/03/01/rails-3-plugins---part-1---the-big-picture/">Use <code>lib/tasks</code> and Railties instead</a>. <code>lib/tasks</code> already works in Rails 2, <code>Railties</code> is a Rails 3 feature but you can use it in combination with the legacy <code>init.rb</code> file to preserve compatibility with both Rails 2 and Rails 3 versions.</p>
<h3>Deprecated Methods</h3>
<p>There are a bunch of Rails 2 methods that are going to be deprecated in Rails 3. Here&#8217;s a not-complete list:</p>
<ul>
<li><code>ActiveRecord::Base.add_to_base(msg)</code> has been deprecated. Use <code>ActiveRecord::Base.add(msg)</code> insted. This method already works in Rails 2.</li>
</ul>
<h2>Rails 3 upgrade</h2>
<p>The steps above are not enough to make your project a real Rails 3 application, they are just a small subset of changes you should apply. The big difference which is also the main advantage compared with all the other changes, is that you don&#8217;t have to wait for Rails 3 to adapt the code. <strong>The more steps you complete now, the less you will have to change while upgrading to Rails 3</strong>.</p>
<p><div class="flash-message with-icon featured clearfix">
<a href="http://thinkcode.tv/catalog/upgrading-rails-3/?utm_source=simonecarletti.com&utm_medium=link&utm_content=message-rails3upgrade&utm_campaign=rails3upgrade"><img src="http://www.simonecarletti.com/images/screencasts/rails3-small.png" height="100" class="alignleft" /></a>
<h4>Upgrading to Rails 3 screencast</h4>
<p>Looking for a Rails 3 screencast? <a href="http://thinkcode.tv/catalog/upgrading-rails-3/?utm_source=simonecarletti.com&utm_medium=link&utm_content=message-rails3upgrade&utm_campaign=rails3upgrade">This one hour screencast is a live example of upgrading a real-world application from Rails 2 to Rails 3.</a></p>
</div></p>
<p>Related posts<ol>
<li><a href='http://www.simonecarletti.com/blog/2009/09/inside-ruby-on-rails-extract_options-from-arrays/' rel='bookmark' title='Understanding Ruby and Rails: extract_options! from Arrays'>Understanding Ruby and Rails: extract_options! from Arrays</a></li>
<li><a href='http://www.simonecarletti.com/blog/2011/09/using-sprockets-without-a-railsrack-project/' rel='bookmark' title='Using Sprockets without a Rails/Rack project'>Using Sprockets without a Rails/Rack project</a></li>
<li><a href='http://www.simonecarletti.com/blog/2009/06/how-to-test-rails-activerecord-named-scopes/' rel='bookmark' title='Testing Rails: How to test Rails ActiveRecord Named Scopes'>Testing Rails: How to test Rails ActiveRecord Named Scopes</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.simonecarletti.com/blog/2010/07/the-way-to-rails-3/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Understanding Ruby and Rails: extract_options! from Arrays</title>
		<link>http://www.simonecarletti.com/blog/2009/09/inside-ruby-on-rails-extract_options-from-arrays/</link>
		<comments>http://www.simonecarletti.com/blog/2009/09/inside-ruby-on-rails-extract_options-from-arrays/#comments</comments>
		<pubDate>Tue, 22 Sep 2009 09:18:21 +0000</pubDate>
		<dc:creator>Simone Carletti</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[activerecord]]></category>
		<category><![CDATA[array]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.simonecarletti.com/blog/?p=481</guid>
		<description><![CDATA[extract_options! extracts the options from the given set of arguments splitting the list of arguments from the options.]]></description>
			<content:encoded><![CDATA[<p><em>This is article is part of my series Understanding Ruby and Rails. Please see the <a href="http://www.simonecarletti.com/blog/2009/09/inside-ruby-on-rails-reading-source-code/">table of contents</a> for the series to view the list of all posts.</em></p>
<p>How many times did you see a method call like the following one in your Rails application?</p>
<div class="codecolorer-container text default code-ruby" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">my_method :arg1<br />
my_method :arg1, :arg2, :argN<br />
my_method :arg1, :foo =&gt; true, :bar =&gt; 1</div></td></tr></tbody></table></div>
<p>What makes <code>my_method</code> quite special is the ability to pass an arbitrary number of parameters (<code>:arg1</code>, <code>:arg2</code>&#8230;) followed by a list of keyword/value options.</p>
<p>This is made possible by a really helpful method provided by <code>ActiveSupport</code> called <code>extract_options!</code>. What this core extension does is to extract the options from the given set of arguments. When no options are available, the method returns a blank Hash.<span id="more-481"></span></p>
<p>Let me show you an example.</p>
<div class="codecolorer-container text default code-ruby" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"># Use args with the splat operation to allow<br />
# an unlimited number of parameters<br />
def my_method(*args)<br />
&nbsp; options = args.extract_options!<br />
&nbsp; puts &quot;Arguments: &nbsp;#{args.inspect}&quot;<br />
&nbsp; puts &quot;Options: &nbsp; &nbsp;#{options.inspect}&quot;<br />
end<br />
<br />
my_method(1, 2)<br />
# Arguments: &nbsp;[1, 2]<br />
# Options: &nbsp; &nbsp;{}<br />
<br />
my_method(1, 2, :a =&gt; :b)<br />
# Arguments: &nbsp;[1, 2]<br />
# Options: &nbsp; &nbsp;{:a=&gt;:b}</div></td></tr></tbody></table></div>
<p><code>extract_options!</code> is largely used in every Rails project and you probably encountered it countless times. It powers the most part of Rails features you use every day including ActionController filters, ActiveRecord validations and finder methods.</p>
<div class="codecolorer-container text default code-ruby" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"># ActionController filters<br />
class MyController &lt; ApplicationController &nbsp; before_filter :my_method, :if =&gt; :execute?, :only =&gt; %w(new)<br />
end<br />
<br />
# ActiveRecord validations and finders<br />
class MyModel &lt; ActiveRecord::Base &nbsp; validates_presence_of :field, :allow_blank =&gt; true<br />
<br />
&nbsp; ...<br />
<br />
&nbsp; def self.my_find<br />
&nbsp; &nbsp; find(:all, :order =&gt; &quot;id&quot;, :limit =&gt; 10)<br />
&nbsp; end<br />
<br />
end</div></td></tr></tbody></table></div>
<p><code>extract_options!</code> allows you to easily extract a list of options from an array of parameters, usually coming from a method invocation.</p>
<p>It isn&#8217;t a standard Ruby method but a Rails Core Extension and you need to require <code>ActiveSupport</code> in order to use it. Also, beware that this is a &#8220;bang&#8221; method, hence it definitely modifies the object it is called on.</p>
<p>Related posts<ol>
<li><a href='http://www.simonecarletti.com/blog/2009/09/inside-ruby-on-rails-reading-source-code/' rel='bookmark' title='Understanding Ruby and Rails: Reading Source Code'>Understanding Ruby and Rails: Reading Source Code</a></li>
<li><a href='http://www.simonecarletti.com/blog/2009/09/inside-ruby-on-rails-benchmarking-your-scripts/' rel='bookmark' title='Understanding Ruby and Rails: Benchmarking your Ruby scripts'>Understanding Ruby and Rails: Benchmarking your Ruby scripts</a></li>
<li><a href='http://www.simonecarletti.com/blog/2009/12/inside-ruby-on-rails-delegate/' rel='bookmark' title='Understanding Ruby and Rails: Delegate'>Understanding Ruby and Rails: Delegate</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.simonecarletti.com/blog/2009/09/inside-ruby-on-rails-extract_options-from-arrays/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Testing Rails: How to test Rails ActiveRecord Named Scopes</title>
		<link>http://www.simonecarletti.com/blog/2009/06/how-to-test-rails-activerecord-named-scopes/</link>
		<comments>http://www.simonecarletti.com/blog/2009/06/how-to-test-rails-activerecord-named-scopes/#comments</comments>
		<pubDate>Wed, 17 Jun 2009 07:37:55 +0000</pubDate>
		<dc:creator>Simone Carletti</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[activerecord]]></category>
		<category><![CDATA[named_scope]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://www.simonecarletti.com/blog/?p=392</guid>
		<description><![CDATA[How to effectively test ActiveRecord named scopes in Rails without querying the database.]]></description>
			<content:encoded><![CDATA[<p>One of my biggest deal when approaching new features in Rails is the correct answer to the question &#8220;<strong>how should I test this?</strong>&#8220;.</p>
<p>Someone would probably assert that <strong>everything you code can be tested</strong> and, even though I perfectly agree with that, I would probably be more interested in how that shiny piece of code can be tested. Rails made the creation of tests a piece of cake, but it&#8217;s not always so easy.</p>
<p>Have you ever tried to test the correct creation of a cookie in Rails 2.2? Have you ever written an helper test that involves routing rules in Rails 2.0? Have you ever created a test to ensure your caching strategy works as expected?</p>
<p>If you answered yes to at least to one of those questions, you probably know what I mean.</p>
<p>The first requirement to write effective tests is to <strong>know what you are playing with</strong>. You can&#8217;t really know how to test an ActiveRecord callback unless you don&#8217;t know how callbacks works in ActiveRecord and, off course, what your hook is supposed to do.</p>
<p>The second suggestion if you get stuck writing a test is to start reading how that feature or the underlying implementation has been tested in the original framework. So, if you need to write a test for your custom Rails <code>foo_tag</code> helper, you probably want to start reading how the Rails team tested the helpers available with the Rails framework. Believe me, you&#8217;ll discover tons of new features just reading the tests.</p>
<p>I don&#8217;t want to go deep further on how to write effective tests, I&#8217;m already writing something special about that topic. This time, let me show you how to test one of the most recent ActiveRecord features: <strong>named_scope</strong>.<span id="more-392"></span></p>
<h2>What are named_scope(s)?</h2>
<p>Named scopes have been introduced in Rails 2.1. Ok, this is probably not the very latest feature, but one of those I have been testing in the &#8220;wrong&#8221; way since a few weeks ago.</p>
<p>Named scopes enables you to define custom ActiveRecord filters to narrow down a database query without explicitly pass conditions or query options. You can also chain multiple scopes to get all the records matching the sum of all the conditions merged altogether.</p>
<p>Look the following example, taken from the great Ryan&#8217;s <a title="Ryan's Scraps: What's New in Edge Rails: Has Finder Functionality" href="http://ryandaigle.com/articles/2008/3/24/what-s-new-in-edge-rails-has-finder-functionality">What&#8217;s New in Edge Rails: Has Finder Functionality</a> blog post.</p>
<div class="codecolorer-container text default code-ruby" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">class User &lt; ActiveRecord::Base<br />
&nbsp; named_scope :active, :conditions =&gt; {:active =&gt; true}<br />
&nbsp; named_scope :inactive, :conditions =&gt; {:active =&gt; false}<br />
&nbsp; named_scope :recent, lambda { { :conditions =&gt; ['created_at &gt; ?', 1.week.ago] } }<br />
end<br />
<br />
# Standard usage<br />
User.active &nbsp; &nbsp;# same as User.find(:all, :conditions =&gt; {:active =&gt; true})<br />
User.inactive # same as User.find(:all, :conditions =&gt; {:active =&gt; false})<br />
User.recent &nbsp; # same as User.find(:all, :conditions =&gt; ['created_at &gt; ?', 1.week.ago])</div></td></tr></tbody></table></div>
<h2>How to test named_scope(s) (the wrong way)</h2>
<p>Now that you know what named scopes are and how they works, at least on the surface, you probably want to know how to test them.</p>
<p>When I first started writing named scope tests, the most obvious way seemed to me to use fixtures. Unfortunately, my fixture files started to be cluttered by fake definitions quickly enough. Tons of records required just to test a single method.</p>
<div class="codecolorer-container text default code-ruby" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"># The following fixtures are used to test the Airport #best named_scope.<br />
# The value for search doesn't match current number of search instances<br />
# but it doesn't really matter in this case.<br />
<br />
&lt;% 10.times do |index| %&gt;<br />
initial_airport_code_ROM_&lt;%= index %&gt;:<br />
&nbsp; search: search_hotels_example<br />
&nbsp; custom_field: initial_airport_code<br />
&nbsp; value: ROM<br />
&lt;% end %&gt;<br />
<br />
&lt;% 5.times do |index| %&gt;<br />
initial_airport_code_FCO_&lt;%= index %&gt;:<br />
&nbsp; search: search_hotels_example<br />
&nbsp; custom_field: initial_airport_code<br />
&nbsp; value: FCO<br />
&lt;% end %&gt;<br />
<br />
&lt;% 5.times do |index| %&gt;<br />
initial_airport_code_RMA_&lt;%= index %&gt;:<br />
&nbsp; search: search_hotels_example<br />
&nbsp; custom_field: initial_airport_code<br />
&nbsp; value: RMA<br />
&lt;% end %&gt;</div></td></tr></tbody></table></div>
<p>Even worse, my code started to be overwhelmed by ugly precondition checks in order to ensure my test didn&#8217;t pass just because of inconsistent fixtures.</p>
<div class="codecolorer-container text default code-ruby" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">def test_recent_should_returns_latest_N_records_ordered_by_created_at<br />
&nbsp; # precondition: ensure the test doesn't pass<br />
&nbsp; # just because there are only 3 users.<br />
&nbsp; assert User.count &gt; 3<br />
<br />
&nbsp; users = User.recent(3).all<br />
&nbsp; assert_equal(3, users.length)<br />
&nbsp; assert_equal(User.find(:all, :limit =&gt; 3, :order =&gt; 'created_at DESC'), users)<br />
end</div></td></tr></tbody></table></div>
<p>Needless to say, the work to maintain all the fixtures was driving me crazy. I couldn&#8217;t believe that was the right way.</p>
<p><a title="Railscasts - Factories not Fixtures" href="http://railscasts.com/episodes/158-factories-not-fixtures">Then comes Factory</a>, and developers started to say factories are better than fixtures. I agree, at least you don&#8217;t have to deal with messy fixtures.</p>
<p>At this point I quickly decided to change my tests from the old fixture-school to the fashionable factory-style.</p>
<div class="codecolorer-container text default code-ruby" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">test &quot;named_scope :latest should return all bookmarks ordered by create_at DESC&quot; do<br />
&nbsp; Bookmark.delete_all<br />
&nbsp; bookmarks = (0..3).map { |t| Factory(:bookmark, :created_at =&gt; t.months.from_now) }<br />
&nbsp; assert_equal bookmarks.reverse, Bookmark.latest<br />
end<br />
<br />
test &quot;named scope :localized&quot; do<br />
&nbsp; Tutorial.delete_all<br />
&nbsp; one = Factory(:tutorial, :language =&gt; languages(:italian))<br />
&nbsp; two = Factory(:tutorial, :language =&gt; languages(:english))<br />
&nbsp; thr = Factory(:tutorial, :language =&gt; languages(:italian))<br />
<br />
&nbsp; assert_equal([one, thr], Tutorial.localized(languages(:italian)).all)<br />
end<br />
<br />
test &quot;named scope :published&quot; do<br />
&nbsp; Tutorial.delete_all<br />
&nbsp; one = Factory(:tutorial, :published =&gt; true)<br />
&nbsp; two = Factory(:tutorial, :published =&gt; false)<br />
&nbsp; thr = Factory(:tutorial, :published =&gt; true)<br />
<br />
&nbsp; assert_equal([one, thr], Tutorial.published)<br />
end</div></td></tr></tbody></table></div>
<p>Yeah, this code started to smell less than the previous one. Do you agree?</p>
<p>But there&#8217;s still something wrong with those tests. Ok they works and they are definitely better than the previous ones or than no tests at all. But there&#8217;s still an unnoticeable smell in the air. No, it&#8217;s not you, don&#8217;t worry.</p>
<p>The question is: <strong>Do you really need to use real active record instances?</strong> <strong>Do you really need to test against the database?</strong> No, you don&#8217;t and you probably won&#8217;t.</p>
<h2>How to test named_scope(s) (the right way)</h2>
<p>There&#8217;s a better way to test named scopes. You can write your tests to test the conditions generated by the named scope instead of the records returned by the query.</p>
<p>Let&#8217;s say you need to test the following named scopes.</p>
<div class="codecolorer-container text default code-ruby" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">class Video &lt; ActiveRecord::Base<br />
&nbsp; named_scope :localized, lambda { |language| { :conditions =&gt; { :language_id =&gt; language.id }}}<br />
&nbsp; named_scope :latest, lambda { |*args| { :limit =&gt; (args.shift || nil), :order =&gt; &quot;#{self.table_name}.created_at DESC&quot; }}<br />
end</div></td></tr></tbody></table></div>
<p>You already wrote these tests using the factory-way.</p>
<div class="codecolorer-container text default code-ruby" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">test &quot;named scope :localized&quot; do<br />
&nbsp; Video.delete_all<br />
<br />
&nbsp; one = Factory(:video, :language =&gt; languages(:italian))<br />
&nbsp; two = Factory(:video, :language =&gt; languages(:english))<br />
&nbsp; thr = Factory(:video, :language =&gt; languages(:italian))<br />
<br />
&nbsp; assert_equal([one, thr], Video.localized(languages(:italian)).all)<br />
end<br />
<br />
test &quot;named_scope :latest(N) should return latest(N) bookmarks ordered by created_at DESC&quot; do<br />
&nbsp; Video.delete_all<br />
&nbsp; videos = (0..3).map { |t| Factory(:video, :created_at =&gt; t.months.from_now) }<br />
&nbsp; assert_equal [videos[3], videos[2]], Video.latest(2)<br />
end<br />
<br />
test &quot;named_scope :latest should return all bookmarks ordered by created_at DESC&quot; do<br />
&nbsp; Video.delete_all<br />
&nbsp; videos = (0..3).map { |t| Factory(:video, :created_at =&gt; t.months.from_now) }<br />
&nbsp; assert_equal videos.reverse, Video.latest<br />
end</div></td></tr></tbody></table></div>
<p>You might be happy to know that there&#8217;s a really wonderful method, named <code>proxy_options</code>, that returns the options set by a named_scope.</p>
<div class="codecolorer-container text default code-ruby" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">p Video.latest.proxy_options<br />
# {:limit=&gt;2, :order=&gt;&quot;videos.created_at DESC&quot;}<br />
<br />
p Video.latest(2).proxy_options<br />
# {:limit=&gt;nil, :order=&gt;&quot;videos.created_at DESC&quot;}</div></td></tr></tbody></table></div>
<p>Isn&#8217;t that cool? Yeah, I know it is!</p>
<p>Now that we know how to get the query filters, we can use them to test our expectations.</p>
<div class="codecolorer-container text default code-ruby" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">test &quot;named scope :localized&quot; do<br />
&nbsp; expected = { :language_id =&gt; languages(:italian).id }<br />
&nbsp; assert_equal &nbsp;expected,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Video.localized(languages(:italian)).proxy_options<br />
end<br />
<br />
test &quot;named_scope :latest(N) should return latest(N) bookmarks ordered by created_at DESC&quot; do<br />
&nbsp; expected = { :limit =&gt; 2, :order =&gt; &quot;videos.created_at DESC&quot; }<br />
&nbsp; assert_equal &nbsp;expected,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Video.latest(2).proxy_options<br />
end<br />
<br />
test &quot;named_scope :latest should return all bookmarks ordered by created_at DESC&quot; do<br />
&nbsp; expected = { :limit =&gt; nil, :order =&gt; &quot;videos.created_at DESC&quot; }<br />
&nbsp; assert_equal &nbsp;expected,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Video.latest.proxy_options<br />
end</div></td></tr></tbody></table></div>
<p>I you want to make your test even more cool, I&#8217;ve found a nice addition reading the <a href="http://github.com/thoughtbot/pacecar/">Thoughbot Pacecar</a> unit tests. You can add an initial <code>respond_to?</code> assertion to make sure you actually defined the named scope before testing it.</p>
<div class="codecolorer-container text default code-ruby" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">test &quot;named scope :localized&quot; do<br />
&nbsp; assert Video.respond_to?(:localized)<br />
&nbsp; expected = { :language_id =&gt; languages(:italian).id }<br />
&nbsp; assert_equal &nbsp;expected,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Video.localized(languages(:italian)).proxy_options<br />
end</div></td></tr></tbody></table></div>
<p>Now that you know how to get access to the named scope options, should probably <strong>avoid wasting resources</strong> creating new records and running active record queries. <strong>Just because you are writing test it doesn&#8217;t mean you don&#8217;t need to care about performances or execution time.</strong></p>
<p>So far, this is the best way I found to test ActiveRecord named scopes. Do you know a better one?</p>
<p>Related posts<ol>
<li><a href='http://www.simonecarletti.com/blog/2009/08/user-profile-permalinks-with-ruby-on-rails-and-authlogic/' rel='bookmark' title='User profile permalinks with Ruby on Rails (and Authlogic)'>User profile permalinks with Ruby on Rails (and Authlogic)</a></li>
<li><a href='http://www.simonecarletti.com/blog/2010/07/the-way-to-rails-3/' rel='bookmark' title='The Road to Rails 3: make your Rails 2.3 project more Rails 3 oriented'>The Road to Rails 3: make your Rails 2.3 project more Rails 3 oriented</a></li>
<li><a href='http://www.simonecarletti.com/blog/2009/04/activerecordmulticonditions-development-discontinued/' rel='bookmark' title='ActiveRecord::MultiConditions development discontinued'>ActiveRecord::MultiConditions development discontinued</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.simonecarletti.com/blog/2009/06/how-to-test-rails-activerecord-named-scopes/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Validating the format of an URL with Rails</title>
		<link>http://www.simonecarletti.com/blog/2009/04/validating-the-format-of-an-url-with-rails/</link>
		<comments>http://www.simonecarletti.com/blog/2009/04/validating-the-format-of-an-url-with-rails/#comments</comments>
		<pubDate>Thu, 30 Apr 2009 06:34:39 +0000</pubDate>
		<dc:creator>Simone Carletti</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[activerecord]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.simonecarletti.com/blog/?p=309</guid>
		<description><![CDATA[A super simple Rails validator for URL based on Ruby URI library.]]></description>
			<content:encoded><![CDATA[<p>Validating the format of an URI is one of those problems that periodically arises when you are validating model attributes in Rails.</p>
<p>There are tons of solutions available on the web, but the 90% of them are usually <strong>based on complex regular expressions</strong> and they often made custom (and perhaps too restrictive) assumptions. This is a small list of the most common &#8220;mistakes&#8221;:</p>
<ul>
<li>Some validators don&#8217;t support custom domain names such as <code>http://simone.weppos</code>, absolutely legal if my application is working behind a custom DNS service</li>
<li>Some validators don&#8217;t support hostnames such as <code>http://localhost</code></li>
<li>Some validators focus on specific URL patterns instead of supporting a common validation mechanism</li>
<li>Some validators don&#8217;t understand that <code>http://www.google.co.uk</code> esists</li>
<li>Some validators rely on a TLD whitelist that often becomes outdates.</li>
</ul>
<p>I&#8217;m working on a project where I need to validate URLs quite often and I decided to approach the problem from an other point of view. I don&#8217;t like to reinvent the wheel, thus I decided to take advantage of <strong>Ruby <code>URI</code> library</strong>.<span id="more-309"></span></p>
<p>This is a super simple validator I wrote. It is based on <code>URI.parse</code>.</p>
<div class="codecolorer-container text default code-ruby" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:300px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"># Validates whether the value of the specified attribute matches the format of an URL,<br />
# as defined by RFC 2396. See URI#parse for more information on URI decompositon and parsing.<br />
#<br />
# This method doesn't validate the existence of the domain, nor it validates the domain itself.<br />
#<br />
# Allowed values include http://foo.bar, http://www.foo.bar and even http://foo.<br />
# Please note that http://foo is a valid URL, as well http://localhost.<br />
# It's up to you to extend the validation with additional constraints.<br />
#<br />
# &nbsp; class Site &lt; ActiveRecord::Base<br />
# &nbsp; &nbsp; validates_format_of :url, :on =&gt; :create<br />
# &nbsp; &nbsp; validates_format_of :ftp, :schemes =&gt; [:ftp, :http, :https]<br />
# &nbsp; end<br />
#<br />
# ==== Configurations<br />
#<br />
# * &lt;tt&gt;:schemes&lt;/tt&gt; - An array of allowed schemes to match against (default is &lt;tt&gt;[:http, :https]&lt;/tt&gt;)<br />
# * &lt;tt&gt;:message&lt;/tt&gt; - A custom error message (default is: &quot;is invalid&quot;).<br />
# * &lt;tt&gt;:allow_nil&lt;/tt&gt; - If set to true, skips this validation if the attribute is +nil+ (default is +false+).<br />
# * &lt;tt&gt;:allow_blank&lt;/tt&gt; - If set to true, skips this validation if the attribute is blank (default is +false+).<br />
# * &lt;tt&gt;:on&lt;/tt&gt; - Specifies when this validation is active (default is &lt;tt&gt;:save&lt;/tt&gt;, other options &lt;tt&gt;:create&lt;/tt&gt;, &lt;tt&gt;:update&lt;/tt&gt;).<br />
# * &lt;tt&gt;:if&lt;/tt&gt; - Specifies a method, proc or string to call to determine if the validation should<br />
# &nbsp; occur (e.g. &lt;tt&gt;:if =&gt; :allow_validation&lt;/tt&gt;, or &lt;tt&gt;:if =&gt; Proc.new { |user| user.signup_step &gt; 2 }&lt;/tt&gt;). &nbsp;The<br />
# &nbsp; method, proc or string should return or evaluate to a true or false value.<br />
# * &lt;tt&gt;:unless&lt;/tt&gt; - Specifies a method, proc or string to call to determine if the validation should<br />
# &nbsp; not occur (e.g. &lt;tt&gt;:unless =&gt; :skip_validation&lt;/tt&gt;, or &lt;tt&gt;:unless =&gt; Proc.new { |user| user.signup_step &lt;= 2 }&lt;/tt&gt;). &nbsp;The<br />
# &nbsp; method, proc or string should return or evaluate to a true or false value.<br />
#<br />
def validates_format_of_url(*attr_names)<br />
&nbsp; require 'uri/http'<br />
<br />
&nbsp; configuration = { :on =&gt; :save, :schemes =&gt; %w(http https) }<br />
&nbsp; configuration.update(attr_names.extract_options!)<br />
<br />
&nbsp; allowed_schemes = [*configuration[:schemes]].map(&amp;:to_s)<br />
<br />
&nbsp; validates_each(attr_names, configuration) do |record, attr_name, value|<br />
&nbsp; &nbsp; begin<br />
&nbsp; &nbsp; &nbsp; uri = URI.parse(value)<br />
<br />
&nbsp; &nbsp; &nbsp; if !allowed_schemes.include?(uri.scheme)<br />
&nbsp; &nbsp; &nbsp; &nbsp; raise(URI::InvalidURIError)<br />
&nbsp; &nbsp; &nbsp; end<br />
<br />
&nbsp; &nbsp; &nbsp; if [:scheme, :host].any? { |i| uri.send(i).blank? }<br />
&nbsp; &nbsp; &nbsp; &nbsp; raise(URI::InvalidURIError)<br />
&nbsp; &nbsp; &nbsp; end<br />
<br />
&nbsp; &nbsp; rescue URI::InvalidURIError =&gt; e<br />
&nbsp; &nbsp; &nbsp; record.errors.add(attr_name, :invalid, :default =&gt; configuration[:message], :value =&gt; value)<br />
&nbsp; &nbsp; &nbsp; next<br />
&nbsp; &nbsp; end<br />
&nbsp; end<br />
end</div></td></tr></tbody></table></div>
<p>The code is also <a href="http://gist.github.com/102138">available as a Gist</a>.</p>
<p>I do have some unit tests, but they are specific to my application and I can&#8217;t post them here. I encourage you to build your own.</p>
<p>I found <a title="thoughtbot's shoulda at master - GitHub" href="http://github.com/thoughtbot/shoulda">shoulda</a> to be particularly helpful in this situation.</p>
<div class="codecolorer-container text default code-ruby" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">class ModelTest &lt; ActiveSupport::TestCase<br />
<br />
&nbsp; VALID_URLS &nbsp; &nbsp;= [<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 'http://godaddy.com', 'http://www.godaddy.com',<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 'https://godaddy.com', 'https://www.godaddy.com',<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 'http://godaddy.host', 'https://godaddy.host',<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ]<br />
&nbsp; INVALID_URLS &nbsp;= [<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 'ftp://godaddy.com',<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 'www.godaddy.com', 'godaddy.com',<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 'http:/godaddy.com',<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ]<br />
<br />
&nbsp; should_allow_values_for :myattr, *VALID_URLS<br />
&nbsp; should_not_allow_values_for :myattr, *INVALID_URLS<br />
<br />
end</div></td></tr></tbody></table></div>
<p>Please note that this validator does not claim to be perfect. As I explained in the documentation, it does not validates some requirements that might be mandatory for your specific application.</p>
<p>Related posts<ol>
<li><a href='http://www.simonecarletti.com/blog/2010/07/the-way-to-rails-3/' rel='bookmark' title='The Road to Rails 3: make your Rails 2.3 project more Rails 3 oriented'>The Road to Rails 3: make your Rails 2.3 project more Rails 3 oriented</a></li>
<li><a href='http://www.simonecarletti.com/blog/2009/06/how-to-test-rails-activerecord-named-scopes/' rel='bookmark' title='Testing Rails: How to test Rails ActiveRecord Named Scopes'>Testing Rails: How to test Rails ActiveRecord Named Scopes</a></li>
<li><a href='http://www.simonecarletti.com/blog/2011/04/rspec-rails-doesnt-render-rails-views-by-default/' rel='bookmark' title='RSpec Rails doesn&#8217;t render Rails views by default'>RSpec Rails doesn&#8217;t render Rails views by default</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.simonecarletti.com/blog/2009/04/validating-the-format-of-an-url-with-rails/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

