<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><!-- generator="wordpress/1.5.2" --><rss 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:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Duncan Beevers</title>
	<link>http://duncan.beevers.net</link>
	<description>simpler</description>
	<pubDate>Wed, 05 Sep 2007 16:33:33 +0000</pubDate>
	<generator>http://wordpress.org/?v=1.5.2</generator>
	<language>en</language>

		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/duncanbeevers" /><feedburner:info uri="duncanbeevers" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Make your controllers filter and block</title>
		<link>http://feedproxy.google.com/~r/duncanbeevers/~3/xXMCFbwCGz4/</link>
		<comments>http://duncan.beevers.net/?p=64#comments</comments>
		<pubDate>Mon, 13 Aug 2007 21:36:24 +0000</pubDate>
		<dc:creator>duncanbeevers</dc:creator>
		
	<category>Uncategorized</category>
		<guid isPermaLink="false">http://duncan.beevers.net/?p=64</guid>
		<description><![CDATA[	Often we want to conditionally execute code based on a User&#8217;s role.
	In Agile Web Development With Rails the before_filter example uses a method called authorize
	before_filter :authorize where authorize is implemented like so:
	
def authorize
  unless User.find_by_id(session[:user_id])
    flash[:notice] = &#34;Please log in&#34;
    redirect_to(:controller => &#34;login&#34;, :action => &#34;login&#34;)
  end
end

	Say [...]]]></description>
			<content:encoded><![CDATA[	<p>Often we want to conditionally execute code based on a User&#8217;s role.</p>
	<p>In <a href="http://www.amazon.com/gp/redirect.html?ie=UTF8&#038;location=http%3A%2F%2Fwww.amazon.com%2FAgile-Development-Rails-Pragmatic-Programmers%2Fdp%2F0977616630%3Fie%3DUTF8%26s%3Dbooks%26qid%3D1187038949%26sr%3D8-1&#038;tag=duncanbeevers-20&#038;linkCode=ur2&#038;camp=1789&#038;creative=9325">Agile Web Development With Rails</a> the before_filter example uses a method called <tt>authorize</tt></p>
	<p><tt>before_filter :authorize</tt> where authorize is implemented like so:</p>
	<pre>
def authorize
  unless User.find_by_id(session[:user_id])
    flash[:notice] = &quot;Please log in&quot;
    redirect_to(:controller => &quot;login&quot;, :action => &quot;login&quot;)
  end
end
</pre>
	<p>Say our controller contains two actions, :index and :show.  And say we&#8217;d like to make :show available to the public while :index requires authorization, we can declare the before_filter like so: <tt>before_filter :authorize, :only => :index</tt></p>
	<p>Now say in the :show action we have one piece of functionality that should only be available to authorized users, but not to anonymous users.  Instead of duplicating the authorize logic in the controller action, we can re-use it!</p>
	<p>Ugly duplication!</p>
	<pre>
def show
  @book = Book.find( params[:book_id] )
  @price = @book.price
  if User.find_by_id( session[:user_id] )
    @wholesale_price = @book.wholesale_price
  end
end
</pre>
	<p>Let&#8217;s make this slightly more descriptive and terrifically flexible.<br />
Start off by renaming the filter method from authorize to authorized_only.  The before_filter becomes <tt>before_filter :authorized_only, :only => :index</tt></p>
	<pre>
def authorized_only &#038;block
  @active_user ||= User.find_by_id( session[:user_id] )
  if @active_user
    yield block if block_given?
  elsif !block_given?
    flash[:notice] = &quot;Please log in&quot;
    redirect_to(:controller => &quot;login&quot;, :action => &quot;login&quot;)
  end
end
</pre>
	<p>By passing an optional block to the method, we can use the same authorized_only semantics in the controller show method.</p>
	<pre>
def show
  @book = Book.find( params[:book_id] )
  @price = @book.price
  authorized_only do
    @wholesale_price = @book.wholesale_price
  end
end
</pre>
	<p>I&#8217;d actually recommend moving the flash and redirect functionality to a new method called by another before_filter that relies on the state generated by the initial call to authorized_only, but that&#8217;s just a point of abstraction, not actual functionality.</p>
	<p>This method is simple to extend to various roles, keeping the semantics for each User role consistent, such as admin_only, anonymous_only, owner_only, etc&hellip;, all of which clearly communicate the permissions required for access to the indicated functionality.  Additionally, adding similar block-evaluating methods to your helpers lets you conditionally include blocks of markup based on a User&#8217;s role.
</p>
<img src="http://feeds.feedburner.com/~r/duncanbeevers/~4/xXMCFbwCGz4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRSS>http://duncan.beevers.net/?feed=rss2&amp;p=64</wfw:commentRSS>
	<feedburner:origLink>http://duncan.beevers.net/?p=64</feedburner:origLink></item>
		<item>
		<title>iTerm keyboard niceness</title>
		<link>http://feedproxy.google.com/~r/duncanbeevers/~3/9TVzBmynaWg/</link>
		<comments>http://duncan.beevers.net/?p=63#comments</comments>
		<pubDate>Fri, 20 Jul 2007 22:44:05 +0000</pubDate>
		<dc:creator>duncanbeevers</dc:creator>
		
	<category>Programming</category>
		<guid isPermaLink="false">http://duncan.beevers.net/?p=63</guid>
		<description><![CDATA[	
&#8997; &#8592; and &#8997; &#8594; are used almost universally on the Mac to step the cursor forward and backwards, respectively, one word at a time.  Home and End are used likewise, to move the cursor to the beginning or end of a line.
	Wanting to use these features in iTerm, I added the following entries [...]]]></description>
			<content:encoded><![CDATA[	<p><img src="http://www.innoq.com/blog/st/apps/images/iTerm.png" align="left" /><br />
&#8997; &larr; and &#8997; &rarr; are used almost universally on the Mac to step the cursor forward and backwards, respectively, one word at a time.  Home and End are used likewise, to move the cursor to the beginning or end of a line.</p>
	<p>Wanting to use these features in <a href="http://iterm.sourceforge.net/">iTerm</a>, I added the following entries to the Global Keyboard Bundle (&#8984; &#8997; B)</p>
	<dl>
	<dt>&#8997; &larr;</dt>
	<dd>
	<ul>
	<li>Key: cursor left</li>
	<li>Modifier: Option</li>
	<li>Action: send escape sequence</li>
	<li>Escape sequence: b</li>
	</ul>
	</dd>
	<dt>&#8997; &rarr;</dt>
	<dd>
	<ul>
	<li>Key: cursor right</li>
	<li>Modifier: Option</li>
	<li>Action: send escape sequence</li>
	<li>Escape sequence: f</li>
	</ul>
	</dd>
	<dt>Home</dt>
	<dd>
	<ul>
	<li>Key: home</li>
	<li>Modifier: none</li>
	<li>Action: send hex code</li>
	<li>Hex code: 01</li>
	<li>High interception priority</li>
	</ul>
	</dd>
	<dt>End</dt>
	<dd>
	<ul>
	<li>Key: end</li>
	<li>Modifier: none</li>
	<li>Action: send hex code</li>
	<li>Hex code: 05</li>
	<li>High interception priority</li>
	</ul>
	</dd>
	</dl>
	<table>
	<tbody>
	<tr>
	<td><a href="http://picasaweb.google.com/duncanbeevers/ITermKeyboardSettings/photo#5089405057481193122"><img src="http://lh3.google.com/duncanbeevers/RqEy71k-NqI/AAAAAAAAAr4/MWFo1HstcUA/s144/ctrl_left.jpg" /></a></td>
	<td><a href="http://picasaweb.google.com/duncanbeevers/ITermKeyboardSettings/photo#5089405057481193138"><img src="http://lh3.google.com/duncanbeevers/RqEy71k-NrI/AAAAAAAAAsA/4WbXvnOOglk/s144/ctrl_right.jpg" /></a></td>
	</tr>
	<tr>
	<td><a href="http://picasaweb.google.com/duncanbeevers/ITermKeyboardSettings/photo#5089405057481193122">left one word</a></td>
	<td><a href="http://picasaweb.google.com/duncanbeevers/ITermKeyboardSettings/photo#5089405057481193138">right one word</a></td>
	</tr>
	<tr>
	<td><a href="http://picasaweb.google.com/duncanbeevers/ITermKeyboardSettings/photo#5089405061776160466"><img src="http://lh4.google.com/duncanbeevers/RqEy8Fk-NtI/AAAAAAAAAsQ/EpEEg6AKQhk/s144/home.jpg" /></a></td>
	<td><a href="http://picasaweb.google.com/duncanbeevers/ITermKeyboardSettings/photo#5089405057481193154"><img src="http://lh3.google.com/duncanbeevers/RqEy71k-NsI/AAAAAAAAAsI/8gHSquJxjQI/s144/end.jpg" /></a></td>
	</tr>
	<tr>
	<td><a href="http://picasaweb.google.com/duncanbeevers/ITermKeyboardSettings/photo#5089405061776160466">beginning of line</a></td>
	<td><a href="http://picasaweb.google.com/duncanbeevers/ITermKeyboardSettings/photo#5089405057481193154">end of line</a></td>
	</tr>
	</tbody>
	</table>
<img src="http://feeds.feedburner.com/~r/duncanbeevers/~4/9TVzBmynaWg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRSS>http://duncan.beevers.net/?feed=rss2&amp;p=63</wfw:commentRSS>
	<feedburner:origLink>http://duncan.beevers.net/?p=63</feedburner:origLink></item>
		<item>
		<title>link_to_remote goes where?</title>
		<link>http://feedproxy.google.com/~r/duncanbeevers/~3/q9adpM3pHZY/</link>
		<comments>http://duncan.beevers.net/?p=62#comments</comments>
		<pubDate>Thu, 19 Jul 2007 23:50:59 +0000</pubDate>
		<dc:creator>duncanbeevers</dc:creator>
		
	<category>Programming</category>
		<guid isPermaLink="false">http://duncan.beevers.net/?p=62</guid>
		<description><![CDATA[	A list of great things:
	
	link_to_remote
	ARTS
	assert_select
	
	These tools make it easy to test the effects of our RJS, but how can we make sure that link_to_remote actually hits the right endpoint?
	Well, here&#8217;s a stab in the dark, in your test_helper.rb.
	
def assert_link_to_remote link_text, link_to_remote_url
  assert_select &#8216;a[onclick*=&#8221;new Ajax.Request(\'&#8217; + link_to_remote_url + &#8216;\&#8217;&#8221;]&#8217;, :text =&#62; link_text
end

	
]]></description>
			<content:encoded><![CDATA[	<p>A list of great things:</p>
	<ul>
	<li><a href="http://api.rubyonrails.org/classes/ActionView/Helpers/PrototypeHelper.html#M000527">link_to_remote</a></li>
	<li><a href="http://glu.ttono.us/articles/2006/05/29/guide-test-driven-rjs-with-arts">ARTS</a></li>
	<li><a href="http://labnotes.org/svn/public/ruby/rails_plugins/assert_select/cheat/assert_select.html">assert_select</a></li>
	</ul>
	<p>These tools make it easy to test the effects of our RJS, but how can we make sure that <tt>link_to_remote</tt> actually hits the right endpoint?</p>
	<p>Well, here&#8217;s a stab in the dark, in your <tt>test_helper.rb</tt>.</p>
	<pre><tt>
def assert_link_to_remote link_text, link_to_remote_url
  assert_select &#8216;a[onclick*=&#8221;new Ajax.Request(\'&#8217; + link_to_remote_url + &#8216;\&#8217;&#8221;]&#8217;, :text =&gt; link_text
end
</tt></pre>
	<blockquote>
<img src="http://feeds.feedburner.com/~r/duncanbeevers/~4/q9adpM3pHZY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRSS>http://duncan.beevers.net/?feed=rss2&amp;p=62</wfw:commentRSS>
	<feedburner:origLink>http://duncan.beevers.net/?p=62</feedburner:origLink></item>
		<item>
		<title>UFO Pizza</title>
		<link>http://feedproxy.google.com/~r/duncanbeevers/~3/FX7ZkluG1jg/</link>
		<comments>http://duncan.beevers.net/?p=60#comments</comments>
		<pubDate>Fri, 01 Jun 2007 18:13:24 +0000</pubDate>
		<dc:creator>duncanbeevers</dc:creator>
		
	<category>Living</category>
		<guid isPermaLink="false">http://duncan.beevers.net/?p=60</guid>
		<description><![CDATA[	The best Gyro&#8217;s in Portland are at UFO Pizza.  Unfortunately all their contact info on the &#8216;net seems to be out-of-date.
	So I went in to talk to Alkis, and got the straight dope.  Here it is, for those who like their gyros Greek.
	UFO Pizza
6024 NE Glisan Ave.
Portland OR
Phone: (503) 234 7654
Hours: Monday - [...]]]></description>
			<content:encoded><![CDATA[	<p>The best Gyro&#8217;s in Portland are at UFO Pizza.  Unfortunately all their contact info on the &#8216;net seems to be out-of-date.</p>
	<p>So I went in to talk to Alkis, and got the straight dope.  Here it is, for those who like their gyros Greek.</p>
	<p>UFO Pizza<br />
<a href="http://maps.google.com/maps?f=q&#038;hl=en&#038;q=6024+NE+Glisan+Ave.+portland+or&#038;sll=37.0625,-95.677068&#038;sspn=33.710275,75.410156&#038;ie=UTF8&#038;ll=45.526825,-122.601371&#038;spn=0.007276,0.018411&#038;z=16&#038;iwloc=addr&#038;om=1">6024 NE Glisan Ave.</a><br />
Portland OR<br />
Phone: (503) 234 7654<br />
Hours: Monday - Saturday, 11am - 9pm</p>
	<p>Seriously.
</p>
<img src="http://feeds.feedburner.com/~r/duncanbeevers/~4/FX7ZkluG1jg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRSS>http://duncan.beevers.net/?feed=rss2&amp;p=60</wfw:commentRSS>
	<feedburner:origLink>http://duncan.beevers.net/?p=60</feedburner:origLink></item>
		<item>
		<title>validates_not_format_of</title>
		<link>http://feedproxy.google.com/~r/duncanbeevers/~3/1Meyzyg29lU/</link>
		<comments>http://duncan.beevers.net/?p=59#comments</comments>
		<pubDate>Mon, 21 May 2007 23:48:48 +0000</pubDate>
		<dc:creator>duncanbeevers</dc:creator>
		
	<category>Programming</category>
		<guid isPermaLink="false">http://duncan.beevers.net/?p=59</guid>
		<description><![CDATA[	validates_format_of is great when you want to make sure an attribute conforms to a regular expression.  Sometimes though, you need to negate a regular expression match (grep -v.)  Here&#8217;s a  custom validator that wraps that functionality up, as well as some more human-readable permutations such as validates_does_not_begin_with_the_word to keep the intention of [...]]]></description>
			<content:encoded><![CDATA[	<p><code><a href="http://api.rubyonrails.com/classes/ActiveRecord/Validations/ClassMethods.html#M000945">validates_format_of</a></code> is great when you want to make sure an attribute conforms to a regular expression.  Sometimes though, you need to negate a regular expression match (<code>grep -v</code>.)  Here&#8217;s a  custom validator that wraps that functionality up, as well as some more human-readable permutations such as <code>validates_does_not_begin_with_the_word</code> to keep the intention of the code clearer.</p>
	<pre>
# Helpful validations based on negations of regular expressions.
# validates_not_format_of takes an array of attributes,
#  a regular expression to apply to them,
#  and an optional hash of configuration options.
#
# All other validations take an array of attributes,
#  a word or list of words to act upon,
#  and an optional hash of configuration options.
#
# Examples:
# validates_does_have_the_words :username, :description, %w(chicken yellow coward), :ignore_case =&gt; true
# In this case, the model will not be valid if the username or description attributes contain any of the
# restricted words, regardless of case.
#
module ActiveRecord
  module Validations
    module ClassMethods
	
      # Negates a regular expression match against an attribute.
      # Similar to grep -v
      #
      def validates_not_format_of(*attr_names)
        configuration = { :message =&gt; ActiveRecord::Errors.default_error_messages[:invalid], :on =&gt; :save, :with =&gt; nil }
        configuration.update(attr_names.pop) if attr_names.last.is_a?(Hash)
	
        raise(ArgumentError, \"A regular expression must be supplied as the :with option of the configuration hash\") unless configuration[:with].is_a?(Regexp)
	
        validates_each(attr_names, configuration) do |record, attr_name, value|
          record.errors.add(attr_name, configuration[:message]) if value.to_s =~ configuration[:with]
        end
      end
	
      def validates_does_not_begin_with_the_word(*attr_names)
        validates_attributes_not_format_of_block(attr_names) { |word| \"^#{word}\" }
      end
      alias :validates_does_not_begin_with_the_words :validates_does_not_begin_with_the_word
	
      # Validates an attribute does not end with the provided string, or strings.
      # Examples:
      # validates_does_not_end_with_the_word :username, '2000'
      #  or
      # validates_does_not_end_with_the_words :username, %w(xxx ooo 666 McFly)
      #
      def validates_does_not_end_with_the_word(*attr_names)
        validates_attributes_not_format_of_block(attr_names) { |word| \"#{word}$\" }
      end
      alias :validates_does_not_end_with_the_words :validates_does_not_end_with_the_word
	
      # Validates an attribute does not contain disallowed words
      # Examples:
      # validates_does_not_have_the_word :username, 'admin'
      #  or
      # validates_does_not_have_the_words :username, %w(admin guest moderator)
      #
      def validates_does_not_have_the_word(*attr_names)
        validates_attributes_not_format_of_block(attr_names) { |word| word }
      end
      alias :validates_does_not_have_the_words :validates_does_not_have_the_word
	
      def validates_is_not_the_word(*attr_names)
        validates_attributes_not_format_of_block(attr_names) { |word| \"^#{word}$\" }
      end
      alias :validates_is_not_the_words :validates_is_not_the_word
	
      private
      # The block supplied to validates_attributes_not_format_of_block must yield a string
      # that can be converted into a regular expression by Regexp.new
      #
      # The argument supplied to the block is a string that has been regular-expression-quoted,
      # and is safe to use without further escaping.
      #
      # You can pass options for how the regular expression is created in the final options hash.
      # Either use :ignore_case =&gt; true
      #  or
      # :regexp_options =&gt; Fixnum
      # either of which will be passed as the 2nd argument to Regexp.new, with :regexp_options taking precedence
      # See documentation on Regexp.new for more information on allowable values for :regexp_options
      #
      def validates_attributes_not_format_of_block(attr_names, &amp;block)
        options = attr_names.last.is_a?(Hash) ? attr_names.pop : { }
        word = attr_names.pop
	
        words = word.respond_to?(:each) ? word : [ word ]
        regexp_options = options.delete(:regexp_options) || options.delete(:ignore_case)
	
        restriction = Regexp.new(words.map { |w| \"(#{yield Regexp.quote(w.to_s)})\" }.join('|'), regexp_options)
	
        configuration = {
          # Overridable default configuration
          :message =&gt; 'is not valid',
          :on =&gt; :save
        }.merge(options || {}).merge(
          # Mandatory default configuration
          :with =&gt; restriction
        )
        validates_not_format_of attr_names, configuration
      end
    end
  end
end
</pre>
<img src="http://feeds.feedburner.com/~r/duncanbeevers/~4/1Meyzyg29lU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRSS>http://duncan.beevers.net/?feed=rss2&amp;p=59</wfw:commentRSS>
	<feedburner:origLink>http://duncan.beevers.net/?p=59</feedburner:origLink></item>
		<item>
		<title>ActiveRecord Pagination for Destructive Migrations</title>
		<link>http://feedproxy.google.com/~r/duncanbeevers/~3/ouVEUxNTVXs/</link>
		<comments>http://duncan.beevers.net/?p=56#comments</comments>
		<pubDate>Fri, 08 Dec 2006 02:57:34 +0000</pubDate>
		<dc:creator>duncanbeevers</dc:creator>
		
	<category>Programming</category>
		<guid isPermaLink="false">http://duncan.beevers.net/?p=56</guid>
		<description><![CDATA[	When you need to make a one-time change to one of your models, a natural tool to use is Rails Migrations.  At a first go, you might try something simple, along these lines:
	The Na&#239;ve Approach
	
class UpdateUsersWithoutDefaultAvatars &#60; ActiveRecord::Migration
  def self.up
    options = { :order => &#34;id&#34;, :conditions =&#62; &#34;avatar IS [...]]]></description>
			<content:encoded><![CDATA[	<p>When you need to make a one-time change to one of your models, a natural tool to use is <a href="http://cheat.errtheblog.com/s/migrations/">Rails Migrations</a>.  At a first go, you might try something simple, along these lines:</p>
	<h3>The Na&iuml;ve Approach</h3>
	<pre>
class UpdateUsersWithoutDefaultAvatars &lt; ActiveRecord::Migration
  def self.up
    options = { :order => &quot;id&quot;, :conditions =&gt; &quot;avatar IS NULL&quot; }
    User.find(:all).each do |user|
      user.reset_avatar!
    end
  end
	
  def self.down
  end
end
</pre>
	<p>Not bad for a first try, but if we look at <a href="http://caboo.se/doc/classes/ActiveRecord/Base.html#M006395"><tt>ActiveRecord::Base#find_by_sql</tt></a> (to which <tt>find</tt> calls are eventually delegated) we see the following:</p>
	<pre>
def find_by_sql(sql)
  connection.select_all(sanitize_sql(sql), &quot;#{name} Load&quot;).collect! { |record| instantiate(record) }
end
</pre>
	<p>The kicker is right there at the call to <tt>instantiate</tt> where a fully-populated model instance is created.  This means that depending on your <tt>:conditions</tt>, you might have <strong>all</strong> of those records in-memory simultaneously.</p>
	<p>As the number of records returned by your <tt>find</tt> increases, the situation becomes simply untenable.</p>
	<p>Instead, a paged approach can help, <strong>but don&#8217;t get too eager, this code is still not acceptable for production use</strong>.</p>
	<h3>Hidden Dangers</h3>
	<pre>
class UpdateUsersWithoutDefaultAvatars &lt; ActiveRecord::Migration
  def self.up
    options = { :order =&gt; &quot;id&quot;, :conditions =&gt; &quot;avatar IS NULL&quot; }
    per_page = 10
    (0..User.count(options)).step(per_page) do |offset|
    User.find(:all, options.dup.merge({ :limit =&gt; per_page, :offset =&gt; offset })).each do |user|
      user.reset_avatar!
    end
  end
	
  def self.down
  end
end
</pre>
	<p>The astute reader may note that for each user, call <tt>reset_avatar!</tt>.  Now, you can&#8217;t see the internals of this function, but perhaps it&#8217;s safe to suspect that it modifies a user&#8217;s <tt>avatar</tt> attribute.  Fine, as that&#8217;s its intended purpose, but what about our <tt>:conditions</tt> clause?</p>
	<p>For each page of users we <i>fix</i>, our overall count goes down, and our offset skips over records that should have been modified.</p>
	<p>A simple solution would be to grab the first pageful of users, perform the operation on them, then request the <i>next</i> <strong>first</strong> pageful of users, as the ones we just modified no longer fall under our conditions clause.</p>
	<p>Should we write this special-case for when the operation being performed on the model is destructive?  How can we more elegantly implement this visitor?</p>
	<p>In order to squeeze out this kind of super-performance, I chose to extend <tt>ActiveRecord::Base</tt>.  Originally, it was simply out of convenience, but as you&#8217;ll see, access to <tt>ActiveRecord::Base</tt>&#8216; private instance method <tt>construct_finder_sql</tt> is key.</p>
	<h3>Efficiency</h3>
	<pre>
module ActiveRecord
  class Base
    def each_by_page per_page, options = {}, &#038;block
      sql = construct_finder_sql(options.dup.merge({ :select =&gt; &quot;id&quot; }))
      all_ids = connection.select_all(sql).map { |h| h[&quot;id&quot;] }
      at_a_time = 0..(per_page-1)
      begin
        all_ids.slice!(at_a_time).each do |ids|
          find(:all, :conditions =&gt; [ &quot;id IN (?)&quot;, ids ] ).each &#038;block
        end
      end until all_ids.empty?
    end
  end
end
</pre>
	<p>and in the migration:</p>
	<pre>
class UpdateUsersWithoutDefaultAvatars &lt; ActiveRecord::Migration
  def self.up
    options = { :order =&gt; &quot;id&quot;, :conditions =&gt; &quot;avatar IS NULL&quot; }
    User.each_by_page(10) { user.reset_avatar! }
  end
	
  def self.down
  end
end
</pre>
	<p>First we use our privileged access to <tt>construct_finder_sql</tt> to build a query that will return only the <tt>:id</tt>s of the records we want to work with.  This will be a large SQL hit, and may require pagination of its own, but the memory footprint is tiny compared to fully instantiating each object, even when your query returns thousands or tens-of-thousands of records.</p>
	<p>Results from feeding SQL directly into <tt>connection</tt> are returned as an array of hashes.  Since all we&#8217;re really interested in is the <tt>id</tt> of each row, (the only member of the hash), we perform a simple mapping on each entry.</p>
	<p><i>As an aside, I imagine there&#8217;s a simpler way to flatten out this array than what I&#8217;ve shown.  Let me know if you&#8217;ve got a really killer method.</i></p>
	<p>Now that we&#8217;ve got our <tt>id</tt>s, we can chop out manageable pieces, instantiate, and modify until the array of <tt>id</tt>s to be operated on is empty, all with no risk of records coming back in any way other than we intended.</p>
	<p><i>Update</i><br />
<a href="http://rcoder.net/">rcoder</a> notes:</p>
	<blockquote><p>
If the update is only affects the User model, ‘User.update_all’ may be sufficient; otherwise, a quick call into ‘ActiveRecord::Base.connection.execute(”…”)’ may be called for.
</p></blockquote>
	<p>A good point, when the modification of the model is simple and the conditions apply only to the table you&#8217;re working with; however, I feel this paged approach has at least two significant advantages:</p>
	<ul>
	<li>Records modified by <tt>each_by_page</tt> are still subject to validations, whereas <tt>update_all</tt> or pumping SQL directly into <tt>Model.connection</tt> bypasses these safety checks.</li>
	<li>Multi-table joins can be trivially incorporated into the <tt>conditions</tt>, whereas crafting, and re-crafting SQL is slightly more error-prone.</li>
	</ul>
	<p>If all your models needed to be updated regularly, it might be worthwhile to look at implementing this a little closer to the steel, but I feel that especially in the case of migrations, the additional clarity and sanity-checking provided by staying within Rails outweigh the performance benefits gained by doing things by hand.
</p>
<img src="http://feeds.feedburner.com/~r/duncanbeevers/~4/ouVEUxNTVXs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRSS>http://duncan.beevers.net/?feed=rss2&amp;p=56</wfw:commentRSS>
	<feedburner:origLink>http://duncan.beevers.net/?p=56</feedburner:origLink></item>
		<item>
		<title>Ruby Advent Calendar</title>
		<link>http://feedproxy.google.com/~r/duncanbeevers/~3/jmENSNU7Ky4/</link>
		<comments>http://duncan.beevers.net/?p=54#comments</comments>
		<pubDate>Fri, 01 Dec 2006 21:53:32 +0000</pubDate>
		<dc:creator>duncanbeevers</dc:creator>
		
	<category>Programming</category>
		<guid isPermaLink="false">http://duncan.beevers.net/?p=54</guid>
		<description><![CDATA[	Ruby Inside has just opened up the first treat in their Ruby Advent Calendar and it things are off to a great start.  The Amazon S3 services library they demonstrate greatly simplifies the integration of off-site asset storage from within your application, and for those who live in the terminal, it even provides a [...]]]></description>
			<content:encoded><![CDATA[	<p>Ruby Inside has just opened up the first treat in their <a href="http://www.rubyinside.com/advent2006/">Ruby Advent Calendar</a> and it things are off to a great start.  The Amazon S3 services library they demonstrate <strong>greatly</strong> simplifies the integration of off-site asset storage from within your application, and for those who live in the terminal, it even provides a specialized interactive shell for driving the library.  Very cool.</p>
	<p>I can&#8217;t wait to see what else they have in store.
</p>
<img src="http://feeds.feedburner.com/~r/duncanbeevers/~4/jmENSNU7Ky4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRSS>http://duncan.beevers.net/?feed=rss2&amp;p=54</wfw:commentRSS>
	<feedburner:origLink>http://duncan.beevers.net/?p=54</feedburner:origLink></item>
		<item>
		<title>Setting up Ruby on Rails on Mac OS X</title>
		<link>http://feedproxy.google.com/~r/duncanbeevers/~3/Qwme6sA0YzI/</link>
		<comments>http://duncan.beevers.net/?p=53#comments</comments>
		<pubDate>Sat, 11 Nov 2006 02:48:32 +0000</pubDate>
		<dc:creator>duncanbeevers</dc:creator>
		
	<category>Programming</category>
		<guid isPermaLink="false">http://duncan.beevers.net/?p=53</guid>
		<description><![CDATA[	Following the purchase of a new MacBook Core 2 Duo, I needed to get a Rails development environment up-and-running quickly.  After experiencing the hassle of setting things up manually, I explored some simpler alternatives and was able to go from out-of-box to a comfortable working environment in under 2 hours, avoid the mire of [...]]]></description>
			<content:encoded><![CDATA[	<p>Following the purchase of a new MacBook Core 2 Duo, I needed to get a Rails development environment up-and-running quickly.  After experiencing the hassle of <a href="http://www.robbyonrails.com/articles/2006/05/29/install-ruby-rails-and-postgresql-on-osx">setting things up manually</a>, I explored some simpler alternatives and was able to go from out-of-box to a comfortable working environment in under 2 hours, avoid the mire of DarwinPorts, and never insert physical media.  So here&#8217;s the bundle of software I&#8217;ve found essentially indispensable.</p>
	<h2>Comprehensive List, for the impatient</h2>
	<ul>
	<li><a href="http://quicksilver.blacktree.com/">Quicksilver</a></li>
	<li><a href="http://www.getfirefox.com">Firefox 2.0</a>
	<ul>
	<li><a href="http://www.google.com/tools/firefox/browsersync/">Google Browser Sync</a></li>
	<li><a href="https://addons.mozilla.org/firefox/1843/">Firebug</a></li>
	<li><a href="https://addons.mozilla.org/firefox/60/">Web Developer&#8217;s Toolbar</a></li>
	<li><a href="http://www.openqa.org/selenium-ide/download.action">OpenQA Selenium IDE</a></li>
	<li><a href="https://addons.mozilla.org/firefox/1865/">Adblock Plus</a></li>
	</ul>
	</li>
	<li><a href="http://www.adiumx.com/">Adium</a></li>
	<li><a href="http://iterm.sourceforge.net/download.shtml">iTerm</a></li>
	<li><a href="http://www.macromates.com/">Textmate</a></li>
	<li><a href="http://locomotive.raaum.org/">Locomotive</a>
	<ul>
<li><a href="http://locomotive.raaum.org/bundles/index.html">rMagick Bundle</a></li>
</ul>
	</li>
	<li><a href="http://dev.mysql.com/downloads/mysql/5.0.html#Mac_OS_X">MySQL</a></li>
	<li><a href="http://dev.mysql.com/downloads/gui-tools/5.0.html#OSX">MySQL GUI tools</a></li>
	<li>Subversion (<a href="http://www.codingmonkeys.de/mbo/articles/2006/09/13/subversion-1-4-0">Martin Ott&#8217;s 1.4 build</a>)</li>
	<li><a href="http://mail.google.com/mail/help/notifier/notifier_mac.html">Google Notifier</a></li>
	</ul>
	<h2>Up and Running</h2>
	<p>I imagine that you may already have a basic Mac environment set up for your everyday use, including Instant Messaging, so I&#8217;ll skip right to what the developers want.  Mac OS X 10.4.8 ships with Ruby 1.8.2 installed, but for Rails development you&#8217;ll want at least 1.8.4 (<a href="http://nikolay.com/articles/2006/08/28/ruby-1-8-5-released">1.8.5 break <tt>breakpointer</tt></a>) which is exactly what Locomotive comes with (along with Rails 1.1.6, no edge goodness, but the security vulnerability is patched.)</p>
	<p>Go ahead and grab Locomotive and install per usual.  You can use Locomotive to bootstrap a new project, or you can import an existing project and launch a terminal from Locomotive in that project&#8217;s context, but first, let&#8217;s make sure your Locomotive is ready for some real action.</p>
	<p>The default bundle included with Locomotive doesn&#8217;t include rmagick, which can be notoriously difficult to install under OS X.  Go ahead and download the rmagick Locomotive bundle from the Locomotive site and drop it into your Bundles directory, <tt>/Applications/Locomotive2/Bundles</tt> by default.</p>
	<h2>Importing an existing project into Locomotive</h2>
	<p>If you haven&#8217;t checked an existing project out of SVN yet, or you aren&#8217;t using SVN, first install Martin Ott&#8217;s build of SVN 1.4.  As of this writing, the Mac build at Metissian is still at 1.3, which may work for your project, but why linger?  Once SVN is installed, check your project out.  I install something like this.<br />
<code><br />
mkdir ~/Projects<br />
mkdir ~/Projects/my_project<br />
svn co http://svn.myhost.com ~/Projects/my_project<br />
</code></p>
	<p>Enter your credentials, and glaze over as your terminal scrolls&hellip;</p>
	<p>Once checkout is complete, in Locomotive, add an existing project: Applications &rarr; Add existing&hellip;</p>
	<p>Enter the path of your project, <tt>~/Projects/my_project</tt> and select the rmagick bundle from the framework dropdown.</p>
	<p>Once your application is recognized by Locomotive, you can select and launch a terminal window: Applications &rarr; Open Terminal</p>
	<h2>Making your Locomotive environment persistent</h2>
	<p>Once the Terminal is open, check out your environment, perhaps try typing <tt>ruby -v</tt> or <tt>rake -T</tt>.</p>
	<p>At the top of your terminal (or iTerm) window, you should see a line something like <tt>source /private/var/tmp/folders.501/TemporaryItems/1DFEAB12-1424-4833-A7E0-26AB557E2034-1783-00001E4A46F9938A.environment.bash</tt></p>
	<p>Select and copy this line, and in your terminal type.<br />
<tt><br />
mkdir ~/lib<br />
cp /private/var/tmp/folders.501/TemporaryItems/1DFEAB12-1424-4833-A7E0-26AB557E2034-1783-00001E4A46F9938A.environment.bash ~/lib/locomotive.bash<br />
</tt></p>
	<p>If you&#8217;re not interested in switching to your rails application path whenever you spawn a new terminal, modify the new <tt>locomotive.bash</tt> file.  If you&#8217;ve got Textmate installed, you can issue the command <tt>mate ~/lib/locomotive.bash</tt> and remove the last line of the file.</p>
	<p>In order to load this file whenever you open a terminal window, you can modify your <tt>.bash_profile</tt>.</p>
	<p>Issue the command <tt>mate ~/.bash_profile</tt> and add the line <tt>source ~/lib/locomotive.bash</tt> to the top of the file.  Any additional shell customizations can be added to your <tt>.bash_profile</tt> following the sourcing of the Locomotive script.</p>
	<h2>Closing</h2>
	<p>Once Locomotive is installed and persisted, you needn&#8217;t actually launch the Locomotive application proper again if you don&#8217;t wish.  Gems can be installed as usual and will be placed into the Locomotive directory, so wiping Locomotive will keep your system sparkling.
</p>
<img src="http://feeds.feedburner.com/~r/duncanbeevers/~4/Qwme6sA0YzI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRSS>http://duncan.beevers.net/?feed=rss2&amp;p=53</wfw:commentRSS>
	<feedburner:origLink>http://duncan.beevers.net/?p=53</feedburner:origLink></item>
		<item>
		<title>Setting up RadRails 0.7.1 on Windows XP</title>
		<link>http://feedproxy.google.com/~r/duncanbeevers/~3/ZXucxt_yVl0/</link>
		<comments>http://duncan.beevers.net/?p=50#comments</comments>
		<pubDate>Thu, 21 Sep 2006 19:17:03 +0000</pubDate>
		<dc:creator>duncanbeevers</dc:creator>
		
	<category>Programming</category>
		<guid isPermaLink="false">http://duncan.beevers.net/?p=50</guid>
		<description><![CDATA[	RadRails released version 0.7.1 (download) on September 14th so I decided to walk through getting it set up with an in-progress project.
	First, some basic configuration needs to be done to let RadRails know where a few key binaries are.  tshine&#8217;s tutorial walks you through this basic setup.
In summary, with some tweaks:
	
	Specify ruby interpreter: Window [...]]]></description>
			<content:encoded><![CDATA[	<p>RadRails released version 0.7.1 (<a href="">download</a>) on September 14th so I decided to walk through getting it set up with an in-progress project.</p>
	<p>First, some basic configuration needs to be done to let RadRails know where a few key binaries are.  <a href="http://www.radrails.org/blog/2006/9/16/radrails-0-7-1-and-windows-xp-how-to-configure">tshine&#8217;s tutorial</a> walks you through this basic setup.<br />
In summary, with some tweaks:</p>
	<ul>
	<li>Specify ruby interpreter: Window &rarr; Preferences&hellip; &rarr; Ruby &rarr; Installed Interpreters &rarr; Add &rarr;
	<ul>
<li>Interpreter Name: <code>Ruby</code></li>
	<li>Location <code>c:\ruby\bin\ruby.exe</code></li>
	</ul>
	</li>
	<li>Specify Ri/rdoc paths: Window &rarr; Preferences&hellip; &rarr; Ruby &rarr; Ri/rdoc &rarr;
	<ul>
<li>RDoc path: <code>c:\ruby\bin\rdoc</code></li>
	<li>Ri path: <code>c:\ruby\bin\ri</code></li>
	</ul>
	</li>
	<li>Specify rails, rake, and mongrel binaries: Window &rarr; Preferences&hellip; &rarr; Rails &rarr; Configuration &rarr;
<ul>
	<li>Rails path: <code>c:\ruby\bin\rails</code></li>
	<li>Rake path: <code>c:\ruby\bin\rake</code></li>
	<li>Mongrel path: <code>c:\ruby\bin\mongrel_rails</code></li>
	</ul>
	</li>
	</ul>
	<p>If you&#8217;re a TextMate fan, as many Railers are, you&#8217;ll appreciate Corban Brook&#8217;s<br />
<a href="http://schf.uc.org/articles/2006/09/18/textmate-like-template-syntax-for-radrails">TextMate accelerator template</a>.</p>
	<p>A quick tip: If you&#8217;re not already using <a href="http://subversion.tigris.org/">Subversion</a>, get your Rails project on it.  If you are on it, RadRails can quickly associate with your repository, bringing Subversions features seamlessly into your IDE.</p>
	<p>If your Subversion repository is only accessible through an SSH tunnel, Martin Woodward&#8217;s <a href="http://www.woodwardweb.com/java/000155.html">walk-through</a> provides  helpful advice.  One note, for my company&#8217;s Subversion repository I had to ask RadRails to use JavaSVN instead of JavaHL in order to avoid <code>client out of date</code> errors.  If you experience the same issue, you can reach the option from Window &rarr; Preferences&hellip; &rarr; Team &rarr; SVN &rarr; SVN Interface: JavaSVN (Pure Java)</p>
	<p>Once I had the SVN client configured, I was able to import my existing project as a RadRails project;</p>
	<ul>
	<li>Create new project in workspace: File &rarr; New&hellip; SVN &rarr; Checkout Projects from SVN</li>
	<li>Configure repository information: Create new repository location &rarr; Next</li>
	<li>Url: <code>svn+ssh://username@svnhost/projectpath/</code> &rarr; Next</li>
	<li>Select root folder for your application: <code>RAILS_ROOT</code> &rarr; Next</li>
	<li>Select setup method: Check out as project configured using the New Project Wizard &rarr; Finish</li>
	<li>Select project type: Rails &rarr; Rails Project &rarr; Next</li>
	<li>Configure project:
<ul>
	<li>Project name: <code>Your Project Name</code></li>
	<li><strong>check</strong> Use default location (note: If your project is already checked-out locally, you specify the local path where it resides, but the project will be re-checked out and any uncommitted local changes will be lost.)</li>
	<li><strong>uncheck</strong> Generate Rails application skeleton</li>
	<li><strong>uncheck</strong> Create a WEBrick server</li>
	<li><strong>check</strong> Create a Mongrel server</li>
	<li><strong>uncheck</strong> Disable table pluralization</li>
	</ul>
Finish</li>
	</ul>
	<p>Though debugging support in RadRails is still experimental, if you&#8217;re feeling adventurous you may benefit from Richard Robert&#8217;s post on <a href="http://richtextblog.blogspot.com/2006/09/radrails-all-is-forgiven.html">live debugging</a>.
</p>
<img src="http://feeds.feedburner.com/~r/duncanbeevers/~4/ZXucxt_yVl0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRSS>http://duncan.beevers.net/?feed=rss2&amp;p=50</wfw:commentRSS>
	<feedburner:origLink>http://duncan.beevers.net/?p=50</feedburner:origLink></item>
		<item>
		<title>uTorrent Web Interface</title>
		<link>http://feedproxy.google.com/~r/duncanbeevers/~3/b0q3rwzm0gc/</link>
		<comments>http://duncan.beevers.net/?p=51#comments</comments>
		<pubDate>Wed, 20 Sep 2006 17:59:22 +0000</pubDate>
		<dc:creator>duncanbeevers</dc:creator>
		
		<guid isPermaLink="false">http://duncan.beevers.net/?p=51</guid>
		<description><![CDATA[	My favorite BitTorrent client, &#181;Torrent released a beta version a few days ago which includes an oft-requested web-interface.
	If you haven&#8217;t already checked it out, you might get a kick out of some its features; bandwidth scheduling, bandwidth limiting (global / per-torrent), and RSS downloading, to name just a few.
	And with the new web interface, the [...]]]></description>
			<content:encoded><![CDATA[	<p>My favorite BitTorrent client, <a href="http://www.utorrent.com/">&micro;Torrent</a> released a beta version a few days ago which includes an oft-requested web-interface.</p>
	<p>If you haven&#8217;t already checked it out, you might get a kick out of some its features; bandwidth scheduling, bandwidth limiting (global / per-torrent), and RSS downloading, to name just a few.</p>
	<p>And with the new web interface, the features of this lightweight, nimble client are accessible to more people than ever.
</p>
<img src="http://feeds.feedburner.com/~r/duncanbeevers/~4/b0q3rwzm0gc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRSS>http://duncan.beevers.net/?feed=rss2&amp;p=51</wfw:commentRSS>
	<feedburner:origLink>http://duncan.beevers.net/?p=51</feedburner:origLink></item>
	</channel>
</rss>

