<?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"?><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: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/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Ernie Miller</title>
	
	<link>http://erniemiller.org</link>
	<description>No, I don't work in NYC, DC, or the valley, and I'm cool with that.</description>
	<lastBuildDate>Wed, 11 Jan 2012 14:33:08 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/erniemiller" /><feedburner:info uri="erniemiller" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Valium 0.5.0, and the future of Valium/attr_bucket</title>
		<link>http://feedproxy.google.com/~r/erniemiller/~3/u8jI8E_LY38/</link>
		<comments>http://erniemiller.org/2012/01/11/valium-0-5-0-and-the-future-of-valium-attr_bucket/#comments</comments>
		<pubDate>Wed, 11 Jan 2012 14:33:08 +0000</pubDate>
		<dc:creator>Ernie</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[attr_bucket]]></category>
		<category><![CDATA[gems]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[valium]]></category>

		<guid isPermaLink="false">http://erniemiller.org/?p=1051</guid>
		<description><![CDATA[I just released Valium 0.5.0. If you were getting single-element array values back when using value(s)_of against a loaded collection, this is now fixed. Thanks to gamov for the report! In other news, if you&#8217;ve been following Rails 3.2 news, you may have noticed that Rails core is getting functionality very similar to Valium and [...]]]></description>
			<content:encoded><![CDATA[<p>I just released Valium 0.5.0. If you were getting single-element array values back when using value(s)_of against a loaded collection, this is now fixed. Thanks to <a href="https://github.com/gamov">gamov</a> for the report! In other news, if you&#8217;ve been following Rails 3.2 news, you may have noticed that Rails core is getting functionality very similar to Valium and attr_bucket, two of my smaller gems. What&#8217;s that mean for these gems?</p>
<p><span id="more-1051"></span></p>
<h2>Pluckety pluck pluck</h2>
<p>First up, Rails 3.2 has added a <tt>pluck</tt> method, which functions a lot like Valium, minus the ability to re-use already-loaded attributes and select multiple columns. I <a href="https://github.com/rails/rails/pull/3871">made an attempt</a> to get the Valium implementation in to replace pluck, but it was rejected. Valium is currently working just fine for all 3.x versions of Rails, so given the missing functionality (and unfortunate naming) of pluck, I&#8217;ll continue to maintain it. It&#8217;s a small enough library that the maintenance overhead is minimal.</p>
<h2>The attribute store</h2>
<p>Rails 3.2 has also added something called the <a href="http://edgeguides.rubyonrails.org/3_2_release_notes.html#active-record">Active Record Store</a>. At first glance, it looks pretty similar to <a href="http://erniemiller.org/projects/attr_bucket/">attr_bucket</a>, a library I cooked up last year to satisfy a need in one of my own apps. It allows for a simple database-backed key-value store that piggybacks on the AR serialized attribute support.</p>
<p>Based on a quick review of the <a href="https://github.com/rails/rails/blob/master/activerecord/lib/active_record/store.rb">Active Record Store code</a>, the implementation in core is, similarly to pluck, pretty simplistic. At this point, I plan to continue to maintain attr_bucket as well. It&#8217;s way overdue for some love to allow the use of alternate coders and such in 3.1+.</p>
<h2>Conclusion</h2>
<p>In the end, the increased visibility for this kind of functionality in core should only be good for Valium and attr_bucket, as people who may not have been aware that such functionality had already been developed will now have reason to go looking for gems when they exhaust the core implementations&#8217; capabilities. As is so often the case in open source, everyone wins. :)</p>
<img src="http://feeds.feedburner.com/~r/erniemiller/~4/u8jI8E_LY38" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://erniemiller.org/2012/01/11/valium-0-5-0-and-the-future-of-valium-attr_bucket/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://erniemiller.org/2012/01/11/valium-0-5-0-and-the-future-of-valium-attr_bucket/</feedburner:origLink></item>
		<item>
		<title>TextMate 2 + rmate = Awesome</title>
		<link>http://feedproxy.google.com/~r/erniemiller/~3/KFfeiBwBwP8/</link>
		<comments>http://erniemiller.org/2011/12/12/textmate-2-rmate-awesome/#comments</comments>
		<pubDate>Mon, 12 Dec 2011 23:44:23 +0000</pubDate>
		<dc:creator>Ernie</dc:creator>
				<category><![CDATA[Blog]]></category>

		<guid isPermaLink="false">http://erniemiller.org/?p=1035</guid>
		<description><![CDATA[I heard TextMate 2 will be released tomorrow and decided to try it out. One really cool thing that was added to TM2 is the rmate script. This is a nifty little script that will let you edit files on a remote server through your running instance of TextMate 2. Here&#8217;s how to get it [...]]]></description>
			<content:encoded><![CDATA[<p>I heard <a href="http://news.ycombinator.com/item?id=3344881" title="TextMate 2">TextMate 2 will be released tomorrow</a> and decided to try it out. One really cool thing that was added to TM2 is the <tt>rmate</tt> script. This is a nifty little script that will let you edit files on a remote server through your running instance of TextMate 2. Here&#8217;s how to get it working using SSH tunneling.<br />
<span id="more-1035"></span></p>
<h2>Verify it&#8217;s enabled</h2>
<p><div id="attachment_1036" class="wp-caption alignright" style="width: 160px"><a href="http://erniemiller.org/wp-content/uploads/2011/12/TextMate-2-Terminal-Preferences.png"><img src="http://erniemiller.org/wp-content/uploads/2011/12/TextMate-2-Terminal-Preferences-150x150.png" alt="TextMate 2 Terminal Preferences" title="TextMate 2 Terminal Preferences" width="150" height="150" class="size-thumbnail wp-image-1036" /></a><p class="wp-caption-text">TM2 Terminal Preferences</p></div>On the current TM2 alpha, the default is to enable rmate for local clients, as shown here. That&#8217;s just fine, because we want to encrypt our file editing activity via SSH tunnel, anyway. As far as TextMate&#8217;s concerned, our <tt>rmate</tt> <em>is</em> local.</p>
<p>Just verify that the &#8220;Accept rmate connections&#8221; checkbox is checked, &#8220;Access for&#8221; is set to &#8220;local clients&#8221; and note the port number (52698 be default) or set it to one of your choosing.</p>
<p>Once you&#8217;ve done so, click on the &#8220;rmate&#8221; link in the preference&#8217;s descriptive text to open the rmate script in a TextMate window. Copy the script&#8217;s contents.</p>
<h2>The Tunnel o&#8217; (TextMate 2) Love</h2>
<p>If you&#8217;re not familiar with SSH tunneling, all you need to know for the purposes of setting this up is that SSH allows you to send your traffic destined for certain ports over the SSH connection to your local machine (possibly to an alternate port). SSH to a server you&#8217;d like to edit some files on, using the following command:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="sh" style="font-family:monospace;">ssh -R 52698:localhost:52698 &lt;user&gt;@&lt;server&gt;</pre></div></div>

<p></code></p>
<p>Be sure to replace 52698 with the port you chose, if you altered it.</p>
<p>This command says that for the duration of your SSH session, any connections to port 52698 on the remote machine will have their traffic forwarded on to your local machine&#8217;s port 52698, where your running TextMate 2 instance will happily accept it.</p>
<h2>Copy the rmate script (first time only)</h2>
<p>We need to get the script installed on the server. Since you&#8217;re already SSHed onto the server, the easiest way to do that is probably just to paste the contents of the script into a new file. Substitute your own editor of (second) choice as appropriate:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="sh" style="font-family:monospace;"># If installing for all users...
sudo vi /usr/local/bin/rmate
# If installing for yourself (make sure it's in your PATH!)... 
vi ~/bin/rmate
# Make it executable
chmod +x &lt;previously-used-directory&gt;/rmate</pre></div></div>

<p></code></p>
<p>Now, if all went well, you should be able to run:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="sh" style="font-family:monospace;">rmate rmate_rocks.txt</pre></div></div>

<p></code></p>
<p>A TextMate window should pop up with a blank file. Type whatever you like into the file (might I suggest &#8220;rmate rocks!&#8221;) and save it. On the server, your rmate_rocks.txt file will have been saved!</p>
<h2>Troubleshooting</h2>
<h3>/usr/bin/env: ruby: No such file or directory</h3>
<p>Your server doesn&#8217;t have Ruby installed. The rmate script is written in Ruby, so you&#8217;ll need to install a Ruby interpreter.</p>
<h3>Warning: remote port forwarding failed for listen port 52698</h3>
<p>Someone else is already using port 52698 on the server for something. No big deal. Disconnect from the server, and choose another port:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="sh" style="font-family:monospace;">ssh -R &lt;my-port-number&gt;:localhost:52698 &lt;user&gt;@&lt;server&gt;</pre></div></div>

<p></code></p>
<p>Now, when you run <tt>rmate</tt>, you&#8217;ll just need to specify the alternate port, like so:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="sh" style="font-family:monospace;">rmate -p &lt;my-port-number&gt; rmate_rocks.txt</pre></div></div>

<p></code></p>
<p>Since the SSH tunneling takes care of forwarding the rmate traffic to 52698 locally, you don&#8217;t have to change any setting in the TextMate 2 Terminal preferences!</p>
<h2>That&#8217;s it!</h2>
<p>I&#8217;m really excited about TextMate 2, and haven&#8217;t gotten to play around with it much yet, but I hope this helps you get started with what I think is one of the coolest new features. Thanks for reading!</p>
<p>[Update 12/14/11: If you want to further simplify your rmate setup, check out <a href="http://jonsimpson.co.uk/log/2011/rmate-ssh-remoteforward">Jon Simpson's writeup</a> on setting up RemoteForward in your SSH configuration file]</p>
<img src="http://feeds.feedburner.com/~r/erniemiller/~4/KFfeiBwBwP8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://erniemiller.org/2011/12/12/textmate-2-rmate-awesome/feed/</wfw:commentRss>
		<slash:comments>26</slash:comments>
		<feedburner:origLink>http://erniemiller.org/2011/12/12/textmate-2-rmate-awesome/</feedburner:origLink></item>
		<item>
		<title>I’m a Machinist! (and you should be, too)</title>
		<link>http://feedproxy.google.com/~r/erniemiller/~3/6d83Pl35m_0/</link>
		<comments>http://erniemiller.org/2011/11/30/im-a-machinist/#comments</comments>
		<pubDate>Wed, 30 Nov 2011 22:33:33 +0000</pubDate>
		<dc:creator>Ernie</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[job]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[rails machine]]></category>

		<guid isPermaLink="false">http://erniemiller.org/?p=1029</guid>
		<description><![CDATA[I joined Rails Machine last month! My title is Lead Solutions Architect, but basically, that just means I get to work with our customers on all sorts of really cool stuff. I also get to help us plan for all sorts of great things that we can&#8217;t yet announce just yet, so stay tuned for [...]]]></description>
			<content:encoded><![CDATA[<p>I joined <a href="http://railsmachine.com" title="Rails Machine">Rails Machine</a> last month! My title is Lead Solutions Architect, but basically, that just means I get to work with our customers on all sorts of really cool stuff. I also get to help us plan for all sorts of great things that we can&#8217;t yet announce just yet, so stay tuned for that.</p>
<p>I&#8217;d been holding off on making this announcement on my weblog until we had something on our company blog, but things are moving quickly, and since it happens that we are looking for another Machinist, I decided that I&#8217;d like to announce that here. So, if you love Web Operations, beer, Rails, ping pong, espresso, and working with awesome customers, then we should talk.</p>
<img src="http://feeds.feedburner.com/~r/erniemiller/~4/6d83Pl35m_0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://erniemiller.org/2011/11/30/im-a-machinist/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://erniemiller.org/2011/11/30/im-a-machinist/</feedburner:origLink></item>
		<item>
		<title>You Should Write a Ruby Gem</title>
		<link>http://feedproxy.google.com/~r/erniemiller/~3/kvU4SEd6lvo/</link>
		<comments>http://erniemiller.org/2011/10/18/you-should-write-a-ruby-gem/#comments</comments>
		<pubDate>Wed, 19 Oct 2011 02:05:59 +0000</pubDate>
		<dc:creator>Ernie</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[conference]]></category>
		<category><![CDATA[rubyconf]]></category>
		<category><![CDATA[speaking]]></category>

		<guid isPermaLink="false">http://erniemiller.org/?p=1025</guid>
		<description><![CDATA[I am one of the &#8220;various presenters&#8221; in the Confreaks video of the lightning talks available here. Scroll to around 18:15 for my talk, &#8220;You Should Write a Ruby Gem&#8221; (but really, you should watch them all!). RubyConf was an awesome time, and attending (and speaking in) the lightning talks was one of the highlights [...]]]></description>
			<content:encoded><![CDATA[<p>I am one of the &#8220;various presenters&#8221; in the Confreaks video of the lightning talks available <a href="http://confreaks.net/videos/741-rubyconf2011-lightning-talks">here</a>. Scroll to around 18:15 for my talk, &#8220;You Should Write a Ruby Gem&#8221; (but really, you should watch them all!). RubyConf was an awesome time, and attending (and speaking in) the lightning talks was one of the highlights of the conference for me. Be sure to check the video out, if you haven&#8217;t already!</p>
<img src="http://feeds.feedburner.com/~r/erniemiller/~4/kvU4SEd6lvo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://erniemiller.org/2011/10/18/you-should-write-a-ruby-gem/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://erniemiller.org/2011/10/18/you-should-write-a-ruby-gem/</feedburner:origLink></item>
		<item>
		<title>A Belated Post on Squeel Sifters</title>
		<link>http://feedproxy.google.com/~r/erniemiller/~3/Uzgt7Nrh0MI/</link>
		<comments>http://erniemiller.org/2011/09/29/a-belated-post-on-squeel-sifters/#comments</comments>
		<pubDate>Thu, 29 Sep 2011 12:15:20 +0000</pubDate>
		<dc:creator>Ernie</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[gem]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[squeel]]></category>

		<guid isPermaLink="false">http://erniemiller.org/?p=1020</guid>
		<description><![CDATA[A few weeks ago, I added an interesting feature to Squeel, and never really said much about it other than a single tweet and a brief reference in the README. I&#8217;m calling the feature &#8220;sifters&#8221;, and I wanted to write a little bit about the purpose they serve. Scopes Fall Short We can all generally [...]]]></description>
			<content:encoded><![CDATA[<p>A few weeks ago, I added an interesting feature to Squeel, and never really said much about it other than a single <a href="https://twitter.com/erniemiller/status/111280426244505600">tweet</a> and a brief reference in the <a href="https://github.com/ernie/squeel#readme">README</a>. I&#8217;m calling the feature &#8220;sifters&#8221;, and I wanted to write a little bit about the purpose they serve.<br />
<span id="more-1020"></span></p>
<h2>Scopes Fall Short</h2>
<p>We can all generally agree on the principle of DRY, or &#8220;Don&#8217;t Repeat Yourself&#8221; when it comes to writing software. In the realm of ActiveRecord, we have a really useful tool in our arsenal to enhance readability and enable easy reuse of query logic. That tool is <tt>scope</tt>, and it needs no introduction.</p>
<p>In the case of adding conditions to a <tt>WHERE</tt> clause, scopes work great, so long as you want to add those conditions against the base model being used in your query. We can just write something like:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> User <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#CC00FF; font-weight:bold;"><span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span></span>
  scope <span style="color:#ff3333; font-weight:bold;">:name_starts_or_ends_with</span>, 
        <span style="color:#CC0066; font-weight:bold;">lambda</span> <span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">|</span>str<span style="color:#006600; font-weight:bold;">|</span> where<span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">&#40;</span>name =~ <span style="color:#996600;">&quot;#{str}%&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">|</span> <span style="color:#006600; font-weight:bold;">&#40;</span>name =~ <span style="color:#996600;">&quot;%#{str}&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#125;</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
User.<span style="color:#9900CC;">name_starts_or_ends_with</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'bob'</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#008000; font-style:italic;"># =&gt; SELECT &quot;users&quot;.* FROM &quot;users&quot;  </span>
     WHERE <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;users&quot;</span>.<span style="color:#996600;">&quot;name&quot;</span> LIKE <span style="color:#996600;">'bob%'</span> OR <span style="color:#996600;">&quot;users&quot;</span>.<span style="color:#996600;">&quot;name&quot;</span> LIKE <span style="color:#996600;">'%bob'</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span></pre></div></div>

<p></code></p>
<p>This works great, for that limited case. But what if we would really like to use that condition against users, but users are part of a join? Scopes fail us, then. </p>
<p>Sure, we could write a scope on, say, an Article class&#8230;</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> Article <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#CC00FF; font-weight:bold;"><span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span></span>
  scope <span style="color:#ff3333; font-weight:bold;">:authored_by_users_with_name_starting_or_ending_with</span>,
        <span style="color:#CC0066; font-weight:bold;">lambda</span> <span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">|</span>str<span style="color:#006600; font-weight:bold;">|</span> joins<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:user</span><span style="color:#006600; font-weight:bold;">&#41;</span>.
                      <span style="color:#9900CC;">where</span><span style="color:#006600; font-weight:bold;">&#123;</span>user <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#40;</span>name =~ <span style="color:#996600;">&quot;#{str}%&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">|</span> <span style="color:#006600; font-weight:bold;">&#40;</span>name =~ <span style="color:#996600;">&quot;%#{str}&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#125;</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p></code></p>
<p>&#8230;but that&#8217;s a bad idea for a few reasons, the most problematic being that now we&#8217;re making assumptions about a User&#8217;s column names from the article class. There&#8217;s also the problem of needing a similar method on any other class we might like to filter based on user names.</p>
<p>It would be great if we had a way to:</p>
<ol>
<li>Write a reusable bundle of conditions against a model&#8217;s attributes in the code of the model it pertains to</li>
<li>Use these condition bundles even through an association</li>
<li>Abstract away the implementation details of the condition</li>
</ol>
<h2>Sifters Fill the Gap</h2>
<p>That&#8217;s exactly what sifters are designed to solve. A sifter is defined similarly to a scope:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"><span style="color:#008000; font-style:italic;"># Define a sifter via a class macro...</span>
sifter <span style="color:#ff3333; font-weight:bold;">:name_starts_or_ends_with</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>str<span style="color:#006600; font-weight:bold;">|</span>
  <span style="color:#006600; font-weight:bold;">&#40;</span>name =~ <span style="color:#996600;">&quot;#{str}%&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">|</span> <span style="color:#006600; font-weight:bold;">&#40;</span>name =~ <span style="color:#996600;">&quot;%#{str}&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#008000; font-style:italic;"># ...or a class method...</span>
<span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">name_starts_or_ends_with</span><span style="color:#006600; font-weight:bold;">&#40;</span>str<span style="color:#006600; font-weight:bold;">&#41;</span>
  squeel<span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">&#40;</span>name =~ <span style="color:#996600;">&quot;#{str}%&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">|</span> <span style="color:#006600; font-weight:bold;">&#40;</span>name =~ <span style="color:#996600;">&quot;%#{str}&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#125;</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p></code></p>
<p>You can then use the sifter by calling <tt>sift</tt> within the Squeel DSL block, with the sifter name and its parameters (this example used only one, but you can write sifters that take as many as you like):</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;">User.<span style="color:#9900CC;">where</span><span style="color:#006600; font-weight:bold;">&#123;</span>sift <span style="color:#ff3333; font-weight:bold;">:name_starts_or_ends_with</span>, <span style="color:#996600;">'bob'</span><span style="color:#006600; font-weight:bold;">&#125;</span>
<span style="color:#008000; font-style:italic;"># =&gt; SELECT &quot;users&quot;.* FROM &quot;users&quot;  </span>
     WHERE <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;users&quot;</span>.<span style="color:#996600;">&quot;name&quot;</span> LIKE <span style="color:#996600;">'bob%'</span> OR <span style="color:#996600;">&quot;users&quot;</span>.<span style="color:#996600;">&quot;name&quot;</span> LIKE <span style="color:#996600;">'%bob'</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
&nbsp;
Article.<span style="color:#9900CC;">joins</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:user</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">where</span><span style="color:#006600; font-weight:bold;">&#123;</span>user.<span style="color:#9900CC;">sift</span> <span style="color:#ff3333; font-weight:bold;">:name_starts_or_ends_with</span>, <span style="color:#996600;">'bob'</span><span style="color:#006600; font-weight:bold;">&#125;</span>
<span style="color:#008000; font-style:italic;"># =&gt; SELECT &quot;articles&quot;.* FROM &quot;articles&quot; </span>
     INNER JOIN <span style="color:#996600;">&quot;users&quot;</span> ON <span style="color:#996600;">&quot;users&quot;</span>.<span style="color:#996600;">&quot;id&quot;</span> = <span style="color:#996600;">&quot;articles&quot;</span>.<span style="color:#996600;">&quot;person_id&quot;</span> 
     WHERE <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;users&quot;</span>.<span style="color:#996600;">&quot;name&quot;</span> LIKE <span style="color:#996600;">'bob%'</span> OR <span style="color:#996600;">&quot;users&quot;</span>.<span style="color:#996600;">&quot;name&quot;</span> LIKE <span style="color:#996600;">'%bob'</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span></pre></div></div>

<p></code></p>
<p>That&#8217;s about it. I hope you find sifters useful!</p>
<img src="http://feeds.feedburner.com/~r/erniemiller/~4/Uzgt7Nrh0MI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://erniemiller.org/2011/09/29/a-belated-post-on-squeel-sifters/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://erniemiller.org/2011/09/29/a-belated-post-on-squeel-sifters/</feedburner:origLink></item>
		<item>
		<title>RubyConf 2011!</title>
		<link>http://feedproxy.google.com/~r/erniemiller/~3/yR97zgiuXus/</link>
		<comments>http://erniemiller.org/2011/09/28/rubyconf-2011/#comments</comments>
		<pubDate>Wed, 28 Sep 2011 19:46:32 +0000</pubDate>
		<dc:creator>Ernie</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[conference]]></category>
		<category><![CDATA[rubyconf]]></category>

		<guid isPermaLink="false">http://erniemiller.org/?p=1018</guid>
		<description><![CDATA[Just checked into my room at the Astor Crowne Plaza for RubyConf 2011. Excited to be here and hope to meet up with as many awesome rubyists as possible. Be sure to say hi, if you see me!]]></description>
			<content:encoded><![CDATA[<p>Just checked into my room at the Astor Crowne Plaza for RubyConf 2011. Excited to be here and hope to meet up with as many awesome rubyists as possible. Be sure to say hi, if you see me!</p>
<img src="http://feeds.feedburner.com/~r/erniemiller/~4/yR97zgiuXus" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://erniemiller.org/2011/09/28/rubyconf-2011/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://erniemiller.org/2011/09/28/rubyconf-2011/</feedburner:origLink></item>
		<item>
		<title>Prevent GoogleBot Overload with Default Nofollow</title>
		<link>http://feedproxy.google.com/~r/erniemiller/~3/WJIrlehdYFo/</link>
		<comments>http://erniemiller.org/2011/09/26/prevent-googlebot-overload-with-default-nofollow/#comments</comments>
		<pubDate>Mon, 26 Sep 2011 16:15:49 +0000</pubDate>
		<dc:creator>Ernie</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[tip]]></category>

		<guid isPermaLink="false">http://erniemiller.org/?p=1012</guid>
		<description><![CDATA[Here&#8217;s a quick tip to exert greater control over which parts of your site a search engine should crawl: modify your link_to helper to make links rel="nofollow" by default. It&#8217;s easy: The Code Just add this to your app&#8217;s application_helper: def link_to&#40;*args, &#38;block&#41; unless block_given? html_options = args&#91;2&#93; &#124;&#124; &#123;&#125; &#160; unless html_options.delete&#40;:follow&#41; if html_options&#91;:rel&#93; [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a quick tip to exert greater control over which parts of your site a search engine should crawl: modify your <tt>link_to</tt> helper to make links <tt>rel="nofollow"</tt> by default. It&#8217;s easy:<br />
<span id="more-1012"></span></p>
<h2>The Code</h2>
<p>Just add this to your app&#8217;s <tt>application_helper</tt>:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;">  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#5A0A0A; font-weight:bold;">link_to</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">*</span>args, <span style="color:#006600; font-weight:bold;">&amp;</span>block<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">unless</span> block_given?
      html_options = args<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">2</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">||</span> <span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">&#125;</span>
&nbsp;
      <span style="color:#9966CC; font-weight:bold;">unless</span> html_options.<span style="color:#5A0A0A; font-weight:bold;">delete</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:follow</span><span style="color:#006600; font-weight:bold;">&#41;</span>
        <span style="color:#9966CC; font-weight:bold;">if</span> html_options<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:rel</span><span style="color:#006600; font-weight:bold;">&#93;</span>
          html_options<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:rel</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">+</span>= <span style="color:#996600;">' nofollow'</span>
        <span style="color:#9966CC; font-weight:bold;">else</span>
          html_options<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:rel</span><span style="color:#006600; font-weight:bold;">&#93;</span> = <span style="color:#996600;">'nofollow'</span>
        <span style="color:#9966CC; font-weight:bold;">end</span>
      <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
      args<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">2</span><span style="color:#006600; font-weight:bold;">&#93;</span> = html_options
    <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
    <span style="color:#9966CC; font-weight:bold;">super</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">*</span>args<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p></code></p>
<p>Use WillPaginate? You may also want to add the following (adapted from <a href="http://stackoverflow.com/questions/4592489/adding-rel-nofollow-to-will-paginate-links-in-rails">this StackOverflow post</a>):</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;">  <span style="color:#9966CC; font-weight:bold;">def</span> will_paginate<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">*</span>args<span style="color:#006600; font-weight:bold;">&#41;</span>
    options = args.<span style="color:#9900CC;">extract_options</span>!
    options<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:renderer</span><span style="color:#006600; font-weight:bold;">&#93;</span> = PaginationNoFollow <span style="color:#9966CC; font-weight:bold;">unless</span> options<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:renderer</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">||</span> options.<span style="color:#5A0A0A; font-weight:bold;">delete</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:follow</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">super</span><span style="color:#006600; font-weight:bold;">&#40;</span>args.<span style="color:#5A0A0A; font-weight:bold;">first</span>, options<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p></code></p>
<p>Set <tt>PaginationNoFollow</tt> up with an initializer:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"><span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'will_paginate/view_helpers/link_renderer'</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">class</span> PaginationNoFollow <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">WillPaginate::ViewHelpers::LinkRenderer</span>
  <span style="color:#9966CC; font-weight:bold;">def</span> rel_value<span style="color:#006600; font-weight:bold;">&#40;</span>page<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">case</span> page
    <span style="color:#9966CC; font-weight:bold;">when</span> <span style="color:#0066ff; font-weight:bold;">@collection</span>.<span style="color:#9900CC;">previous_page</span>; <span style="color:#996600;">'prev nofollow'</span> <span style="color:#006600; font-weight:bold;">+</span> <span style="color:#006600; font-weight:bold;">&#40;</span>page == <span style="color:#006666;">1</span> ? <span style="color:#996600;">' start nofollow'</span> : <span style="color:#996600;">''</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#9966CC; font-weight:bold;">when</span> <span style="color:#0066ff; font-weight:bold;">@collection</span>.<span style="color:#9900CC;">next_page</span>; <span style="color:#996600;">'next nofollow'</span>
    <span style="color:#9966CC; font-weight:bold;">when</span> <span style="color:#006666;">1</span>; <span style="color:#996600;">'start nofollow'</span>
    <span style="color:#9966CC; font-weight:bold;">else</span>
      <span style="color:#996600;">'nofollow'</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p></code></p>
<p>Now, all of your app&#8217;s links will default to <tt>rel="nofollow"</tt>, but obviously you will want <em>some</em> of your links to be crawled. Just add <tt>:follow => true</tt> to the options hash of either <tt>link_to</tt> or <tt>will_paginate</tt> to opt-in specific links for search engine crawling.</p>
<img src="http://feeds.feedburner.com/~r/erniemiller/~4/WJIrlehdYFo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://erniemiller.org/2011/09/26/prevent-googlebot-overload-with-default-nofollow/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://erniemiller.org/2011/09/26/prevent-googlebot-overload-with-default-nofollow/</feedburner:origLink></item>
		<item>
		<title>Valium 0.4.0 released, now with 100% more English</title>
		<link>http://feedproxy.google.com/~r/erniemiller/~3/JOAnbnfWl-c/</link>
		<comments>http://erniemiller.org/2011/09/09/valium-0-4-0-released-now-with-100-more-english/#comments</comments>
		<pubDate>Fri, 09 Sep 2011 13:17:55 +0000</pubDate>
		<dc:creator>Ernie</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[activerecord]]></category>
		<category><![CDATA[gem]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[valium]]></category>

		<guid isPermaLink="false">http://erniemiller.org/?p=1009</guid>
		<description><![CDATA[Just a quick update about Valium 0.4.0. In 0.3.0, I enabled support for extracting attribute values from associations (a la User.posts[:id]). That was awesome, but as it turns out, not too compatible with 3.0.x associations. The solution I figure this is going to be the tip of the iceberg in terms of potential gotchas, so [...]]]></description>
			<content:encoded><![CDATA[<p>Just a quick update about Valium <a href="https://github.com/ernie/valium/tree/v0.4.0" rel="nofollow">0.4.0</a>. In <a href="https://github.com/ernie/valium/tree/v0.3.0" rel="nofollow">0.3.0</a>, I enabled support for extracting attribute values from associations (a la <tt>User.posts[:id]</tt>). That was awesome, but as it turns out, <a href="https://github.com/ernie/valium/issues/4" rel="nofollow">not too compatible with 3.0.x associations</a>.<br />
<span id="more-1009"></span></p>
<h2>The solution</h2>
<p>I figure this is going to be the tip of the iceberg in terms of potential gotchas, so before we get anywhere near to 1.0, I&#8217;m pulling out the <tt>[]</tt> syntax, but adding a new alias: <tt>values_of</tt>. This is just to help code read better &#8212; the functionality is exactly the same. So now, instead of:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"><span style="color:#008000; font-style:italic;"># Don't do this. It won't work anymore. :(</span>
User.<span style="color:#9900CC;">where</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:name</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'ernie'</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:id</span><span style="color:#006600; font-weight:bold;">&#93;</span>
User.<span style="color:#9900CC;">where</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:name</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'ernie'</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:id</span>, <span style="color:#ff3333; font-weight:bold;">:email</span><span style="color:#006600; font-weight:bold;">&#93;</span></pre></div></div>

<p></code></p>
<p>You will write:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"><span style="color:#008000; font-style:italic;"># Do this:</span>
User.<span style="color:#9900CC;">where</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:name</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'ernie'</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">value_of</span> <span style="color:#ff3333; font-weight:bold;">:id</span>
User.<span style="color:#9900CC;">where</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:name</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'ernie'</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">values_of</span> <span style="color:#ff3333; font-weight:bold;">:id</span>, <span style="color:#ff3333; font-weight:bold;">:email</span></pre></div></div>

<p></code></p>
<p>Sorry for the inconvenience. Of course, you&#8217;re always free to alias these to whatever you want, in your own code. Just don&#8217;t blame me if things randomly blow up.</p>
<p>And Pratik, if you&#8217;re reading this: Yes, you <a href="https://twitter.com/lifo/status/106485857481015297">told me so</a>.</p>
<img src="http://feeds.feedburner.com/~r/erniemiller/~4/JOAnbnfWl-c" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://erniemiller.org/2011/09/09/valium-0-4-0-released-now-with-100-more-english/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://erniemiller.org/2011/09/09/valium-0-4-0-released-now-with-100-more-english/</feedburner:origLink></item>
		<item>
		<title>Rails 3.1 and the future of MetaWhere and MetaSearch</title>
		<link>http://feedproxy.google.com/~r/erniemiller/~3/PDN9ksJoB0c/</link>
		<comments>http://erniemiller.org/2011/08/31/rails-3-1-and-the-future-of-metawhere-and-metasearch/#comments</comments>
		<pubDate>Wed, 31 Aug 2011 18:19:11 +0000</pubDate>
		<dc:creator>Ernie</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[gem]]></category>
		<category><![CDATA[meta_search]]></category>
		<category><![CDATA[meta_where]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ransack]]></category>
		<category><![CDATA[squeel]]></category>

		<guid isPermaLink="false">http://erniemiller.org/?p=978</guid>
		<description><![CDATA[Rails 3.1.0 has dropped, and hours later I received my first &#8220;report&#8221; that MetaWhere doesn&#8217;t work with Rails 3.1. For those of you who read this blog or follow me on Twitter, this should come as no surprise. Still, I wanted to make a quick announcement here, if only to have a place to link [...]]]></description>
			<content:encoded><![CDATA[<p>Rails 3.1.0 has dropped, and hours later I received my first &#8220;report&#8221; that MetaWhere doesn&#8217;t work with Rails 3.1. For those of you who read this blog or <a href="http://twitter.com/erniemiller">follow me on Twitter</a>, this should come as no surprise. Still, I wanted to make a quick announcement here, if only to have a place to link people to when they inquire.<br />
<span id="more-978"></span></p>
<h2>MetaWhere -> Squeel</h2>
<p>Some time ago, I blogged about a <a href="http://erniemiller.org/2011/02/18/the-metawhere-2-0-rewrite/">MetaWhere 2.0 rewrite</a>. This rewrite made changes that were extensive enough that I decided to forgo a new version number and jump straight to releasing an entirely new gem, <a href="http://erniemiller.org/2011/04/13/introducing-squeel/">Squeel</a>.</p>
<p>Squeel was written in tandem with the Rails 3.1 beta development process, so it&#8217;s ready to go on day one. It&#8217;s also been backported to 3.0.x since then, and while doing so has required backporting and monkey-patching <a href="https://github.com/ernie/squeel/blob/master/lib/squeel/adapters/active_record/3.0/compat.rb">certain ARel functionality</a> as well, I&#8217;m pretty happy with the results &#8212; all specs are green against Rails 3.0.10.</p>
<p>This means that there is a clear migration path ahead for your app, if you&#8217;re using MetaWhere. You can migrate your MetaWhere queries to the Squeel DSL, first (I&#8217;d encourage you to bypass the Symbol extensions, if you can), then migrate to Rails 3.1 once all your specs are passing.</p>
<p>Why the break with the old? Read the <a href="http://erniemiller.org/2011/02/18/the-metawhere-2-0-rewrite/">original rewrite announcement</a> for the details. In short, I made some bad architectural decisions in MetaWhere. While a lot of people really liked the gem, under the hood, things were a mess. I could have hobbled along with the existing codebase for a while longer, but it was becoming increasingly painful to do so. Besides, I&#8217;d had some new ideas about the way I&#8217;d approach a query DSL. Squeel is what came of those new ideas.</p>
<h2>MetaSearch -> Ransack (eventually)</h2>
<p>MetaSearch is a bit of a different animal. First, its hooks into the ActiveRecord internals are much more shallow than MetaWhere&#8217;s, so it was simpler to port over to 3.1. Second, while Squeel is mostly a superset of MetaWhere, in terms of functionality, Ransack provides fundamentally different types of search functionality, and hasn&#8217;t been completely bulletproofed. I&#8217;m using it in a few projects, myself, but for those who are looking to do a drop-in replacement for MetaSearch, it&#8217;s not quite there, yet.</p>
<p>As such, I&#8217;ve released a v1.1.0 of MetaSearch, which works with Rails 3.1. I&#8217;d still encourage those of you who are starting a new greenfield application on 3.1 to start with Ransack, as this is the long-term path forward.</p>
<p>Many of the same decoupling steps taken in the MetaWhere -> Squeel transition were also taken with Ransack, so it should provide a solid foundation to build on, going forward.</p>
<h2>Conclusion</h2>
<p>Thanks again for using my gems! The steady stream of appreciation and kind words have made working on them a real pleasure (on most days!). Still, I&#8217;m only one guy, and I have clients to serve, and a family I need to love and spend time with. As such, I just can&#8217;t justify spending tons of time maintaining MetaSearch and MetaWhere in addition to their replacements.</p>
<p>I hope you&#8217;ll understand, and I hope that you will give Squeel and Ransack a try!</p>
<img src="http://feeds.feedburner.com/~r/erniemiller/~4/PDN9ksJoB0c" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://erniemiller.org/2011/08/31/rails-3-1-and-the-future-of-metawhere-and-metasearch/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://erniemiller.org/2011/08/31/rails-3-1-and-the-future-of-metawhere-and-metasearch/</feedburner:origLink></item>
		<item>
		<title>Slow MySQL query? I’ll give you a hint.</title>
		<link>http://feedproxy.google.com/~r/erniemiller/~3/CjwzkffMYlo/</link>
		<comments>http://erniemiller.org/2011/08/30/slow-mysql-query-ill-give-you-a-hint/#comments</comments>
		<pubDate>Tue, 30 Aug 2011 20:30:23 +0000</pubDate>
		<dc:creator>Ernie</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[activerecord]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[postgresql]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://erniemiller.org/?p=966</guid>
		<description><![CDATA[I have a confession to make: I&#8217;ve placed too much trust in MySQL&#8217;s query planner. By the phrase, &#8220;too much trust,&#8221; I mean to say, &#8220;any trust, at all, ever.&#8221; Simple Schema So, consider the case of&#8230; Oh, pretty much any Rails application, anywhere. For purposes of this discussion, let&#8217;s consider a simple blog, with [...]]]></description>
			<content:encoded><![CDATA[<p>I have a confession to make: I&#8217;ve placed too much trust in MySQL&#8217;s query planner. By the phrase, &#8220;too much trust,&#8221; I mean to say, &#8220;any trust, at all, ever.&#8221;<br />
<span id="more-966"></span></p>
<h2>Simple Schema</h2>
<p>So, consider the case of&#8230; Oh, pretty much any Rails application, anywhere. For purposes of this discussion, let&#8217;s consider a simple blog, with articles and comments. Here&#8217;s the schema:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"><span style="color:#CC00FF; font-weight:bold;"><span style="color:#6666ff; font-weight:bold;">ActiveRecord::Schema</span></span>.<span style="color:#9900CC;">define</span> <span style="color:#9966CC; font-weight:bold;">do</span>
&nbsp;
  create_table <span style="color:#ff3333; font-weight:bold;">:articles</span>, <span style="color:#ff3333; font-weight:bold;">:force</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>t<span style="color:#006600; font-weight:bold;">|</span>
    t.<span style="color:#9900CC;">string</span>   <span style="color:#ff3333; font-weight:bold;">:title</span>
    t.<span style="color:#9900CC;">text</span>     <span style="color:#ff3333; font-weight:bold;">:body</span>
    t.<span style="color:#9900CC;">boolean</span>  <span style="color:#ff3333; font-weight:bold;">:published</span>, <span style="color:#ff3333; font-weight:bold;">:null</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">false</span>, <span style="color:#ff3333; font-weight:bold;">:default</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">false</span>
    t.<span style="color:#9900CC;">timestamps</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  create_table <span style="color:#ff3333; font-weight:bold;">:comments</span>, <span style="color:#ff3333; font-weight:bold;">:force</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>t<span style="color:#006600; font-weight:bold;">|</span>
    t.<span style="color:#5A0A0A; font-weight:bold;">belongs_to</span> <span style="color:#ff3333; font-weight:bold;">:article</span>
    t.<span style="color:#9900CC;">string</span>     <span style="color:#ff3333; font-weight:bold;">:email</span>
    t.<span style="color:#9900CC;">text</span>       <span style="color:#ff3333; font-weight:bold;">:body</span>
    t.<span style="color:#9900CC;">timestamps</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  add_index <span style="color:#ff3333; font-weight:bold;">:comments</span>, <span style="color:#ff3333; font-weight:bold;">:article_id</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p></code></p>
<p>No rocket science here. Article <tt>has_many :comments</tt> and Comment <tt>belongs_to :article</tt>. We put an index on the <tt>article_id</tt> column in the <tt>comments</tt> table. There&#8217;s a good chance we&#8217;ll end up doing something like chaining from an association scope, which will result in a query for comments by <tt>article_id</tt>.</p>
<h2>Simple Select</h2>
<p>Now, let&#8217;s say we want to do something really simple, like post a list of the 3 most recent comments on our blog&#8217;s homepage. But we only want to include comments against published articles, just in case we make a mistake and need to &#8220;un-publish&#8221; one later &#8212; we don&#8217;t want comments against articles a person can&#8217;t read showing up on our homepage!</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;">Comment.<span style="color:#9900CC;">joins</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:article</span><span style="color:#006600; font-weight:bold;">&#41;</span>.
        <span style="color:#9900CC;">where</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:articles</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#123;</span>:published <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span><span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#41;</span>.
        <span style="color:#9900CC;">order</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'comments.id desc'</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">limit</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">3</span><span style="color:#006600; font-weight:bold;">&#41;</span></pre></div></div>

<p></code></p>
<p>This results in a query that looks like:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span>  <span style="color: #ff0000;">`comments`</span><span style="color: #66cc66;">.*</span> <span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`comments`</span> 
<span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> <span style="color: #ff0000;">`articles`</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #ff0000;">`articles`</span><span style="color: #66cc66;">.</span><span style="color: #ff0000;">`id`</span> <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">`comments`</span><span style="color: #66cc66;">.</span><span style="color: #ff0000;">`article_id`</span> 
<span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #ff0000;">`articles`</span><span style="color: #66cc66;">.</span><span style="color: #ff0000;">`published`</span> <span style="color: #66cc66;">=</span> <span style="color: #cc66cc;">1</span> 
<span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> comments<span style="color: #66cc66;">.</span>id <span style="color: #993333; font-weight: bold;">DESC</span> 
<span style="color: #993333; font-weight: bold;">LIMIT</span> <span style="color: #cc66cc;">3</span></pre></div></div>

<p></code></p>
<h2>Surprising Sluggishness!</h2>
<p>All goes well for a few months. You post a bunch of articles, some of which end up with <strong>huge</strong> comment threads, because you&#8217;re a master of your craft (or a master troll). Next thing you know, you&#8217;ve got 100 articles, around 20,000 comments, and a big performance problem. That simple query you wrote above is taking over half a second to execute, every single time. All of that time, just to retrieve 3 records? Something has got to be wrong with that. You fire up an <tt>EXPLAIN</tt>, and you see this in your query plan:</p>
<p><code>
<pre>Using where; Using temporary; Using filesort</pre>
<p></code></p>
<p>A temporary table and a filesort? Really?? Then you notice that the query planner is starting off with the <tt>articles</tt> table and using the <tt>comments</tt> table&#8217;s index on <tt>article_id</tt> for the join. You wonder for a moment if there is any likely scenario in which this is the most performant optimization plan for this query, given the <tt>ORDER</tt> and <tt>LIMIT</tt> you supplied.</p>
<h2>Subselect or Supplementation</h2>
<p>The fix is easy enough. You can split things into two queries, either using something like <a href="http://erniemiller.org/2011/08/24/the-cure-for-activerecord-instantiation-anxiety-valium/">Valium</a> to get the valid article_ids first, then eliminating the need for the join, or (preferably) using a subquery in the DB:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;"><span style="color:#008000; font-style:italic;"># Rails 3.1 only (Or with Squeel)</span>
Comment.<span style="color:#9900CC;">where</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:article_id</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> Article.<span style="color:#9900CC;">where</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:published</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span>.
        <span style="color:#9900CC;">order</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'comments.id desc'</span><span style="color:#006600; font-weight:bold;">&#41;</span>.
        <span style="color:#9900CC;">limit</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">3</span><span style="color:#006600; font-weight:bold;">&#41;</span></pre></div></div>

<p></code></p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span>  <span style="color: #ff0000;">`comments`</span><span style="color: #66cc66;">.*</span> 
<span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`comments`</span>  
<span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #ff0000;">`comments`</span><span style="color: #66cc66;">.</span><span style="color: #ff0000;">`article_id`</span> 
  <span style="color: #993333; font-weight: bold;">IN</span> <span style="color: #66cc66;">&#40;</span>
    <span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #ff0000;">`articles`</span><span style="color: #66cc66;">.</span><span style="color: #ff0000;">`id`</span> 
    <span style="color: #993333; font-weight: bold;">FROM</span> <span style="color: #ff0000;">`articles`</span>  
    <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #ff0000;">`articles`</span><span style="color: #66cc66;">.</span><span style="color: #ff0000;">`published`</span> <span style="color: #66cc66;">=</span> <span style="color: #cc66cc;">1</span>
  <span style="color: #66cc66;">&#41;</span> 
<span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> comments<span style="color: #66cc66;">.</span>id <span style="color: #993333; font-weight: bold;">DESC</span> 
<span style="color: #993333; font-weight: bold;">LIMIT</span> <span style="color: #cc66cc;">3</span></pre></div></div>

<p></code></p>
<p>An even easier and more performant way, in this case, is to just give MySQL a nudge in the right direction:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="rails" style="font-family:monospace;">Comment.<span style="color:#9900CC;">from</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'comments use index (PRIMARY)'</span><span style="color:#006600; font-weight:bold;">&#41;</span>.
        <span style="color:#9900CC;">joins</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:article</span><span style="color:#006600; font-weight:bold;">&#41;</span>.
        <span style="color:#9900CC;">where</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:articles</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#123;</span>:published <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span><span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#41;</span>.
        <span style="color:#9900CC;">order</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'comments.id desc'</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">limit</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">3</span><span style="color:#006600; font-weight:bold;">&#41;</span></pre></div></div>

<p></code><br />
<code></p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span>  <span style="color: #ff0000;">`comments`</span><span style="color: #66cc66;">.*</span> 
<span style="color: #993333; font-weight: bold;">FROM</span> comments <span style="color: #993333; font-weight: bold;">USE</span> <span style="color: #993333; font-weight: bold;">INDEX</span> <span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">PRIMARY</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> <span style="color: #ff0000;">`articles`</span> <span style="color: #993333; font-weight: bold;">ON</span> <span style="color: #ff0000;">`articles`</span><span style="color: #66cc66;">.</span><span style="color: #ff0000;">`id`</span> <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">`comments`</span><span style="color: #66cc66;">.</span><span style="color: #ff0000;">`article_id`</span> 
<span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #ff0000;">`articles`</span><span style="color: #66cc66;">.</span><span style="color: #ff0000;">`published`</span> <span style="color: #66cc66;">=</span> <span style="color: #cc66cc;">1</span> 
<span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> comments<span style="color: #66cc66;">.</span>id <span style="color: #993333; font-weight: bold;">DESC</span> 
<span style="color: #993333; font-weight: bold;">LIMIT</span> <span style="color: #cc66cc;">3</span></pre></div></div>

<p></code></p>
<h2>Rage Rising</h2>
<p>It&#8217;s great that we have these workarounds available, but I find it more than a little disappointing that the results of <a href="https://gist.github.com/1181915">this benchmark script</a> comparing MySQL, PostgreSQL, and SQLite (yes, SQLite!) look like this:</p>
<p><code>
<pre>
                user     system      total        real
mysql       0.020000   0.010000   0.030000 (  0.617876)
sqlite      0.000000   0.000000   0.000000 (  0.001234)
postgresql  0.000000   0.000000   0.000000 (  0.002423)
</pre>
<p></code></p>
<p>If the query being described were something abnormal, I&#8217;d understand. I expect to need hints and goofy hacks when optimizing an edge case. Not when doing something as simple as outlined above.</p>
<p>Anyway, I hope the above explanation helps you implement workarounds in your own queries, or maybe gives you the last nudge you need to finally get around to checking out PostgreSQL. :)</p>
<img src="http://feeds.feedburner.com/~r/erniemiller/~4/CjwzkffMYlo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://erniemiller.org/2011/08/30/slow-mysql-query-ill-give-you-a-hint/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://erniemiller.org/2011/08/30/slow-mysql-query-ill-give-you-a-hint/</feedburner:origLink></item>
	</channel>
</rss>

