<?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:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
  <channel>
    <title>Darwinweb</title>
    <link>http://darwinweb.net/</link>
    <description>Gabe da Silveira</description>
    <language>en-us</language>
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/darwinweb" type="application/rss+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
      <title>Example of Where Rails Data Integrity Philosophy Fails</title>
      <description>&lt;p&gt;Thanks to Obie I came across a great post about the &lt;a href="http://www.snowgiraffe.com/tech/462/rails-devs-for-foreign-keys/"&gt;Rails Devs for Data Integrity&lt;/a&gt; plugin.  Chalk me up as another supporter of database constraints.  I love Ruby as much as the next guy, but I&amp;#8217;m not going to stick my head in the sand and write broken software just to satisfy some syntactical fetish.  A lot of times I will just do the expeditious thing and follow the Rails way of doing things and stick data constraints in the app; it does the trick enough of the time (note to future self: don&amp;#8217;t hold yourself accountable for having said this).&lt;/p&gt;
&lt;p&gt;However I just came across an extremely simple case where it blows up spectacularly.  If you have an &lt;span class="caps"&gt;AJAX&lt;/span&gt; action that can be rapidly fired, possibly to different app instances, your Ruby code will simply not be up to the task of maintaining data integrity.  Consider the following action:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
@rating = @current_user.ratings.find_or_create_by_film_id(@film.id)
@rating.update_attributes(params[:rating])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Over the course of generating 200,000 ratings, my app ended up with 250 dups due to multiple ratings in rapid succession.  Sure hacking some kind of locking mechanism onto the front-end would probably catch the vast majority of these cases, but a unique key in the database guarantees a solution to the problem.&lt;/p&gt;
&lt;p&gt;Note how this problem has nothing to do with multiple apps talking to the database, future devs performing legacy maintainenance, tyrannical DBAs, or any of the other strawman reasons why we need DB constraints.  In this case I added a unique key because it just works better than the alternatives.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/darwinweb/~4/CqSIkRIYy_o" height="1" width="1"/&gt;</description>
      <author>Gabe da Silveira</author>
      <pubDate>Mon, 04 May 2009 22:19:00 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/darwinweb/~3/CqSIkRIYy_o/example_of_where_rails_data_integrity_philosophy_fails</link>
      <guid isPermaLink="false">http://darwinweb.net/article/example_of_where_rails_data_integrity_philosophy_fails</guid>
    <feedburner:origLink>http://darwinweb.net/article/example_of_where_rails_data_integrity_philosophy_fails</feedburner:origLink></item>
    <item>
      <title>Thinking Sphinx Case Folding Configuration</title>
      <description>&lt;p&gt;Case Folding is what allows searches for &lt;code&gt;pais&lt;/code&gt; or &lt;code&gt;paìs&lt;/code&gt; to match &lt;code&gt;país&lt;/code&gt;.  By default accented characters won&amp;#8217;t even be indexed by Sphinx.  They&amp;#8217;ll be considered word breaks so you would have to search for &lt;code&gt;pa s&lt;/code&gt; to match &lt;code&gt;país&lt;/code&gt;.  I would have thought a standard latin case folding config would be standard for just about everyone using Sphinx, however a cursory Googling didn&amp;#8217;t turn up much.  The &lt;a href="http://yob.id.au/blog/2008/05/08/thinking_sphinx_and_unicode/"&gt;best article&lt;/a&gt; I found as by &lt;a href="http://yob.id.au/"&gt;James Healy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;His config works, but then in the Sphinx wiki I found reference to a &lt;a href="http://speeple.com/unicode-maps.txt"&gt;formatted list&lt;/a&gt; whose formatting and length imparted a certain air of authority.&lt;/p&gt;
&lt;p&gt;I plugged it in to the config given by Mr. Healy and had &lt;span class="caps"&gt;YAML&lt;/span&gt;-related problems.  Using a double-quoted string in &lt;span class="caps"&gt;YAML&lt;/span&gt; will generally collapse everything to one line.  After removing comments from the list the generated config looked good, but then Sphinx choked on the incredibly long line length:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
ERROR: line too long in /Users/dasil003/myapp/config/development.sphinx.conf line 39 col 1.
FATAL: failed to parse config file '/Users/dasil003/myapp/config/development.sphinx.conf'.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The subtleties of &lt;span class="caps"&gt;YAML&lt;/span&gt; parsing are something I&amp;#8217;d rather not commit to memory.  Instead we use experimental science.  What I needed was lines formatted like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
U+00C0-&amp;gt;a, U+00C1-&amp;gt;a, \
U+0180-&amp;gt;b, U+0181-&amp;gt;b, \
U+00C7-&amp;gt;c
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IRb to the rescue:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
&amp;gt;&amp;gt; s = 'U+00C0-&amp;gt;a, U+00C1-&amp;gt;a, \
U+0180-&amp;gt;b, U+0181-&amp;gt;b, \
U+00C7-&amp;gt;c'
&amp;gt;&amp;gt; puts YAML.dump(:key =&amp;gt; s)
--- 
:key: |-
  U+00C0-&amp;gt;a, U+00C1-&amp;gt;a, \
  U+0180-&amp;gt;b, U+0181-&amp;gt;b, \
  U+00C7-&amp;gt;c
&lt;/pre&gt;&lt;p&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Well shucks, that ain&amp;#8217;t so bad.&lt;/p&gt;
&lt;p&gt;The final product which you can drop directly into your &lt;code&gt;sphinx.yml&lt;/code&gt; file (for the development environment anyway):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
development:
  charset_table: |-
    0..9, a..z, _, A..Z-&amp;gt;a..z, \
    U+00C0-&amp;gt;a, U+00C1-&amp;gt;a, U+00C2-&amp;gt;a, U+00C3-&amp;gt;a, U+00C4-&amp;gt;a, U+00C5-&amp;gt;a, U+00E0-&amp;gt;a, U+00E1-&amp;gt;a, U+00E2-&amp;gt;a, U+00E3-&amp;gt;a, U+00E4-&amp;gt;a, U+00E5-&amp;gt;a, U+0100-&amp;gt;a, U+0101-&amp;gt;a, U+0102-&amp;gt;a, U+0103-&amp;gt;a, U+010300-&amp;gt;a, U+0104-&amp;gt;a, U+0105-&amp;gt;a, U+01CD-&amp;gt;a, U+01CE-&amp;gt;a, U+01DE-&amp;gt;a, U+01DF-&amp;gt;a, U+01E0-&amp;gt;a, U+01E1-&amp;gt;a, U+01FA-&amp;gt;a, U+01FB-&amp;gt;a, U+0200-&amp;gt;a, U+0201-&amp;gt;a, U+0202-&amp;gt;a, U+0203-&amp;gt;a, U+0226-&amp;gt;a, U+0227-&amp;gt;a, U+023A-&amp;gt;a, U+0250-&amp;gt;a, U+04D0-&amp;gt;a, U+04D1-&amp;gt;a, U+1D2C-&amp;gt;a, U+1D43-&amp;gt;a, U+1D44-&amp;gt;a, U+1D8F-&amp;gt;a, U+1E00-&amp;gt;a, U+1E01-&amp;gt;a, U+1E9A-&amp;gt;a, U+1EA0-&amp;gt;a, U+1EA1-&amp;gt;a, U+1EA2-&amp;gt;a, U+1EA3-&amp;gt;a, U+1EA4-&amp;gt;a, U+1EA5-&amp;gt;a, U+1EA6-&amp;gt;a, U+1EA7-&amp;gt;a, U+1EA8-&amp;gt;a, U+1EA9-&amp;gt;a, U+1EAA-&amp;gt;a, U+1EAB-&amp;gt;a, U+1EAC-&amp;gt;a, U+1EAD-&amp;gt;a, U+1EAE-&amp;gt;a, U+1EAF-&amp;gt;a, U+1EB0-&amp;gt;a, U+1EB1-&amp;gt;a, U+1EB2-&amp;gt;a, U+1EB3-&amp;gt;a, U+1EB4-&amp;gt;a, U+1EB5-&amp;gt;a, U+1EB6-&amp;gt;a, U+1EB7-&amp;gt;a, U+2090-&amp;gt;a, U+2C65-&amp;gt;a, \
    U+0180-&amp;gt;b, U+0181-&amp;gt;b, U+0182-&amp;gt;b, U+0183-&amp;gt;b, U+0243-&amp;gt;b, U+0253-&amp;gt;b, U+0299-&amp;gt;b, U+16D2-&amp;gt;b, U+1D03-&amp;gt;b, U+1D2E-&amp;gt;b, U+1D2F-&amp;gt;b, U+1D47-&amp;gt;b, U+1D6C-&amp;gt;b, U+1D80-&amp;gt;b, U+1E02-&amp;gt;b, U+1E03-&amp;gt;b, U+1E04-&amp;gt;b, U+1E05-&amp;gt;b, U+1E06-&amp;gt;b, U+1E07-&amp;gt;b, \
    U+00C7-&amp;gt;c, U+00E7-&amp;gt;c, U+0106-&amp;gt;c, U+0107-&amp;gt;c, U+0108-&amp;gt;c, U+0109-&amp;gt;c, U+010A-&amp;gt;c, U+010B-&amp;gt;c, U+010C-&amp;gt;c, U+010D-&amp;gt;c, U+0187-&amp;gt;c, U+0188-&amp;gt;c, U+023B-&amp;gt;c, U+023C-&amp;gt;c, U+0255-&amp;gt;c, U+0297-&amp;gt;c, U+1D9C-&amp;gt;c, U+1D9D-&amp;gt;c, U+1E08-&amp;gt;c, U+1E09-&amp;gt;c, U+212D-&amp;gt;c, U+2184-&amp;gt;c, \
    U+010E-&amp;gt;d, U+010F-&amp;gt;d, U+0110-&amp;gt;d, U+0111-&amp;gt;d, U+0189-&amp;gt;d, U+018A-&amp;gt;d, U+018B-&amp;gt;d, U+018C-&amp;gt;d, U+01C5-&amp;gt;d, U+01F2-&amp;gt;d, U+0221-&amp;gt;d, U+0256-&amp;gt;d, U+0257-&amp;gt;d, U+1D05-&amp;gt;d, U+1D30-&amp;gt;d, U+1D48-&amp;gt;d, U+1D6D-&amp;gt;d, U+1D81-&amp;gt;d, U+1D91-&amp;gt;d, U+1E0A-&amp;gt;d, U+1E0B-&amp;gt;d, U+1E0C-&amp;gt;d, U+1E0D-&amp;gt;d, U+1E0E-&amp;gt;d, U+1E0F-&amp;gt;d, U+1E10-&amp;gt;d, U+1E11-&amp;gt;d, U+1E12-&amp;gt;d, U+1E13-&amp;gt;d, \
    U+00C8-&amp;gt;e, U+00C9-&amp;gt;e, U+00CA-&amp;gt;e, U+00CB-&amp;gt;e, U+00E8-&amp;gt;e, U+00E9-&amp;gt;e, U+00EA-&amp;gt;e, U+00EB-&amp;gt;e, U+0112-&amp;gt;e, U+0113-&amp;gt;e, U+0114-&amp;gt;e, U+0115-&amp;gt;e, U+0116-&amp;gt;e, U+0117-&amp;gt;e, U+0118-&amp;gt;e, U+0119-&amp;gt;e, U+011A-&amp;gt;e, U+011B-&amp;gt;e, U+018E-&amp;gt;e, U+0190-&amp;gt;e, U+01DD-&amp;gt;e, U+0204-&amp;gt;e, U+0205-&amp;gt;e, U+0206-&amp;gt;e, U+0207-&amp;gt;e, U+0228-&amp;gt;e, U+0229-&amp;gt;e, U+0246-&amp;gt;e, U+0247-&amp;gt;e, U+0258-&amp;gt;e, U+025B-&amp;gt;e, U+025C-&amp;gt;e, U+025D-&amp;gt;e, U+025E-&amp;gt;e, U+029A-&amp;gt;e, U+1D07-&amp;gt;e, U+1D08-&amp;gt;e, U+1D31-&amp;gt;e, U+1D32-&amp;gt;e, U+1D49-&amp;gt;e, U+1D4B-&amp;gt;e, U+1D4C-&amp;gt;e, U+1D92-&amp;gt;e, U+1D93-&amp;gt;e, U+1D94-&amp;gt;e, U+1D9F-&amp;gt;e, U+1E14-&amp;gt;e, U+1E15-&amp;gt;e, U+1E16-&amp;gt;e, U+1E17-&amp;gt;e, U+1E18-&amp;gt;e, U+1E19-&amp;gt;e, U+1E1A-&amp;gt;e, U+1E1B-&amp;gt;e, U+1E1C-&amp;gt;e, U+1E1D-&amp;gt;e, U+1EB8-&amp;gt;e, U+1EB9-&amp;gt;e, U+1EBA-&amp;gt;e, U+1EBB-&amp;gt;e, U+1EBC-&amp;gt;e, U+1EBD-&amp;gt;e, U+1EBE-&amp;gt;e, U+1EBF-&amp;gt;e, U+1EC0-&amp;gt;e, U+1EC1-&amp;gt;e, U+1EC2-&amp;gt;e, U+1EC3-&amp;gt;e, U+1EC4-&amp;gt;e, U+1EC5-&amp;gt;e, U+1EC6-&amp;gt;e, U+1EC7-&amp;gt;e, U+2091-&amp;gt;e, \
    U+0191-&amp;gt;f, U+0192-&amp;gt;f, U+1D6E-&amp;gt;f, U+1D82-&amp;gt;f, U+1DA0-&amp;gt;f, U+1E1E-&amp;gt;f, U+1E1F-&amp;gt;f, \
    U+011C-&amp;gt;g, U+011D-&amp;gt;g, U+011E-&amp;gt;g, U+011F-&amp;gt;g, U+0120-&amp;gt;g, U+0121-&amp;gt;g, U+0122-&amp;gt;g, U+0123-&amp;gt;g, U+0193-&amp;gt;g, U+01E4-&amp;gt;g, U+01E5-&amp;gt;g, U+01E6-&amp;gt;g, U+01E7-&amp;gt;g, U+01F4-&amp;gt;g, U+01F5-&amp;gt;g, U+0260-&amp;gt;g, U+0261-&amp;gt;g, U+0262-&amp;gt;g, U+029B-&amp;gt;g, U+1D33-&amp;gt;g, U+1D4D-&amp;gt;g, U+1D77-&amp;gt;g, U+1D79-&amp;gt;g, U+1D83-&amp;gt;g, U+1DA2-&amp;gt;g, U+1E20-&amp;gt;g, U+1E21-&amp;gt;g, \
    U+0124-&amp;gt;h, U+0125-&amp;gt;h, U+0126-&amp;gt;h, U+0127-&amp;gt;h, U+021E-&amp;gt;h, U+021F-&amp;gt;h, U+0265-&amp;gt;h, U+0266-&amp;gt;h, U+029C-&amp;gt;h, U+02AE-&amp;gt;h, U+02AF-&amp;gt;h, U+02B0-&amp;gt;h, U+02B1-&amp;gt;h, U+1D34-&amp;gt;h, U+1DA3-&amp;gt;h, U+1E22-&amp;gt;h, U+1E23-&amp;gt;h, U+1E24-&amp;gt;h, U+1E25-&amp;gt;h, U+1E26-&amp;gt;h, U+1E27-&amp;gt;h, U+1E28-&amp;gt;h, U+1E29-&amp;gt;h, U+1E2A-&amp;gt;h, U+1E2B-&amp;gt;h, U+1E96-&amp;gt;h, U+210C-&amp;gt;h, U+2C67-&amp;gt;h, U+2C68-&amp;gt;h, U+2C75-&amp;gt;h, U+2C76-&amp;gt;h, \
    U+00CC-&amp;gt;i, U+00CD-&amp;gt;i, U+00CE-&amp;gt;i, U+00CF-&amp;gt;i, U+00EC-&amp;gt;i, U+00ED-&amp;gt;i, U+00EE-&amp;gt;i, U+00EF-&amp;gt;i, U+010309-&amp;gt;i, U+0128-&amp;gt;i, U+0129-&amp;gt;i, U+012A-&amp;gt;i, U+012B-&amp;gt;i, U+012C-&amp;gt;i, U+012D-&amp;gt;i, U+012E-&amp;gt;i, U+012F-&amp;gt;i, U+0130-&amp;gt;i, U+0131-&amp;gt;i, U+0197-&amp;gt;i, U+01CF-&amp;gt;i, U+01D0-&amp;gt;i, U+0208-&amp;gt;i, U+0209-&amp;gt;i, U+020A-&amp;gt;i, U+020B-&amp;gt;i, U+0268-&amp;gt;i, U+026A-&amp;gt;i, U+040D-&amp;gt;i, U+0418-&amp;gt;i, U+0419-&amp;gt;i, U+0438-&amp;gt;i, U+0439-&amp;gt;i, U+0456-&amp;gt;i, U+1D09-&amp;gt;i, U+1D35-&amp;gt;i, U+1D4E-&amp;gt;i, U+1D62-&amp;gt;i, U+1D7B-&amp;gt;i, U+1D96-&amp;gt;i, U+1DA4-&amp;gt;i, U+1DA6-&amp;gt;i, U+1DA7-&amp;gt;i, U+1E2C-&amp;gt;i, U+1E2D-&amp;gt;i, U+1E2E-&amp;gt;i, U+1E2F-&amp;gt;i, U+1EC8-&amp;gt;i, U+1EC9-&amp;gt;i, U+1ECA-&amp;gt;i, U+1ECB-&amp;gt;i, U+2071-&amp;gt;i, U+2111-&amp;gt;i, \
    U+0134-&amp;gt;j, U+0135-&amp;gt;j, U+01C8-&amp;gt;j, U+01CB-&amp;gt;j, U+01F0-&amp;gt;j, U+0237-&amp;gt;j, U+0248-&amp;gt;j, U+0249-&amp;gt;j, U+025F-&amp;gt;j, U+0284-&amp;gt;j, U+029D-&amp;gt;j, U+02B2-&amp;gt;j, U+1D0A-&amp;gt;j, U+1D36-&amp;gt;j, U+1DA1-&amp;gt;j, U+1DA8-&amp;gt;j, \
    U+0136-&amp;gt;k, U+0137-&amp;gt;k, U+0198-&amp;gt;k, U+0199-&amp;gt;k, U+01E8-&amp;gt;k, U+01E9-&amp;gt;k, U+029E-&amp;gt;k, U+1D0B-&amp;gt;k, U+1D37-&amp;gt;k, U+1D4F-&amp;gt;k, U+1D84-&amp;gt;k, U+1E30-&amp;gt;k, U+1E31-&amp;gt;k, U+1E32-&amp;gt;k, U+1E33-&amp;gt;k, U+1E34-&amp;gt;k, U+1E35-&amp;gt;k, U+2C69-&amp;gt;k, U+2C6A-&amp;gt;k, \
    U+0139-&amp;gt;l, U+013A-&amp;gt;l, U+013B-&amp;gt;l, U+013C-&amp;gt;l, U+013D-&amp;gt;l, U+013E-&amp;gt;l, U+013F-&amp;gt;l, U+0140-&amp;gt;l, U+0141-&amp;gt;l, U+0142-&amp;gt;l, U+019A-&amp;gt;l, U+01C8-&amp;gt;l, U+0234-&amp;gt;l, U+023D-&amp;gt;l, U+026B-&amp;gt;l, U+026C-&amp;gt;l, U+026D-&amp;gt;l, U+029F-&amp;gt;l, U+02E1-&amp;gt;l, U+1D0C-&amp;gt;l, U+1D38-&amp;gt;l, U+1D85-&amp;gt;l, U+1DA9-&amp;gt;l, U+1DAA-&amp;gt;l, U+1DAB-&amp;gt;l, U+1E36-&amp;gt;l, U+1E37-&amp;gt;l, U+1E38-&amp;gt;l, U+1E39-&amp;gt;l, U+1E3A-&amp;gt;l, U+1E3B-&amp;gt;l, U+1E3C-&amp;gt;l, U+1E3D-&amp;gt;l, U+2C60-&amp;gt;l, U+2C61-&amp;gt;l, U+2C62-&amp;gt;l, \
    U+019C-&amp;gt;m, U+026F-&amp;gt;m, U+0270-&amp;gt;m, U+0271-&amp;gt;m, U+1D0D-&amp;gt;m, U+1D1F-&amp;gt;m, U+1D39-&amp;gt;m, U+1D50-&amp;gt;m, U+1D5A-&amp;gt;m, U+1D6F-&amp;gt;m, U+1D86-&amp;gt;m, U+1DAC-&amp;gt;m, U+1DAD-&amp;gt;m, U+1E3E-&amp;gt;m, U+1E3F-&amp;gt;m, U+1E40-&amp;gt;m, U+1E41-&amp;gt;m, U+1E42-&amp;gt;m, U+1E43-&amp;gt;m, \
    U+00D1-&amp;gt;n, U+00F1-&amp;gt;n, U+0143-&amp;gt;n, U+0144-&amp;gt;n, U+0145-&amp;gt;n, U+0146-&amp;gt;n, U+0147-&amp;gt;n, U+0148-&amp;gt;n, U+0149-&amp;gt;n, U+019D-&amp;gt;n, U+019E-&amp;gt;n, U+01CB-&amp;gt;n, U+01F8-&amp;gt;n, U+01F9-&amp;gt;n, U+0220-&amp;gt;n, U+0235-&amp;gt;n, U+0272-&amp;gt;n, U+0273-&amp;gt;n, U+0274-&amp;gt;n, U+1D0E-&amp;gt;n, U+1D3A-&amp;gt;n, U+1D3B-&amp;gt;n, U+1D70-&amp;gt;n, U+1D87-&amp;gt;n, U+1DAE-&amp;gt;n, U+1DAF-&amp;gt;n, U+1DB0-&amp;gt;n, U+1E44-&amp;gt;n, U+1E45-&amp;gt;n, U+1E46-&amp;gt;n, U+1E47-&amp;gt;n, U+1E48-&amp;gt;n, U+1E49-&amp;gt;n, U+1E4A-&amp;gt;n, U+1E4B-&amp;gt;n, U+207F-&amp;gt;n, \
    U+00D2-&amp;gt;o, U+00D3-&amp;gt;o, U+00D4-&amp;gt;o, U+00D5-&amp;gt;o, U+00D6-&amp;gt;o, U+00D8-&amp;gt;o, U+00F2-&amp;gt;o, U+00F3-&amp;gt;o, U+00F4-&amp;gt;o, U+00F5-&amp;gt;o, U+00F6-&amp;gt;o, U+00F8-&amp;gt;o, U+01030F-&amp;gt;o, U+014C-&amp;gt;o, U+014D-&amp;gt;o, U+014E-&amp;gt;o, U+014F-&amp;gt;o, U+0150-&amp;gt;o, U+0151-&amp;gt;o, U+0186-&amp;gt;o, U+019F-&amp;gt;o, U+01A0-&amp;gt;o, U+01A1-&amp;gt;o, U+01D1-&amp;gt;o, U+01D2-&amp;gt;o, U+01EA-&amp;gt;o, U+01EB-&amp;gt;o, U+01EC-&amp;gt;o, U+01ED-&amp;gt;o, U+01FE-&amp;gt;o, U+01FF-&amp;gt;o, U+020C-&amp;gt;o, U+020D-&amp;gt;o, U+020E-&amp;gt;o, U+020F-&amp;gt;o, U+022A-&amp;gt;o, U+022B-&amp;gt;o, U+022C-&amp;gt;o, U+022D-&amp;gt;o, U+022E-&amp;gt;o, U+022F-&amp;gt;o, U+0230-&amp;gt;o, U+0231-&amp;gt;o, U+0254-&amp;gt;o, U+0275-&amp;gt;o, U+043E-&amp;gt;o, U+04E6-&amp;gt;o, U+04E7-&amp;gt;o, U+04E8-&amp;gt;o, U+04E9-&amp;gt;o, U+04EA-&amp;gt;o, U+04EB-&amp;gt;o, U+1D0F-&amp;gt;o, U+1D10-&amp;gt;o, U+1D11-&amp;gt;o, U+1D12-&amp;gt;o, U+1D13-&amp;gt;o, U+1D16-&amp;gt;o, U+1D17-&amp;gt;o, U+1D3C-&amp;gt;o, U+1D52-&amp;gt;o, U+1D53-&amp;gt;o, U+1D54-&amp;gt;o, U+1D55-&amp;gt;o, U+1D97-&amp;gt;o, U+1DB1-&amp;gt;o, U+1E4C-&amp;gt;o, U+1E4D-&amp;gt;o, U+1E4E-&amp;gt;o, U+1E4F-&amp;gt;o, U+1E50-&amp;gt;o, U+1E51-&amp;gt;o, U+1E52-&amp;gt;o, U+1E53-&amp;gt;o, U+1ECC-&amp;gt;o, U+1ECD-&amp;gt;o, U+1ECE-&amp;gt;o, U+1ECF-&amp;gt;o, U+1ED0-&amp;gt;o, U+1ED1-&amp;gt;o, U+1ED2-&amp;gt;o, U+1ED3-&amp;gt;o, U+1ED4-&amp;gt;o, U+1ED5-&amp;gt;o, U+1ED6-&amp;gt;o, U+1ED7-&amp;gt;o, U+1ED8-&amp;gt;o, U+1ED9-&amp;gt;o, U+1EDA-&amp;gt;o, U+1EDB-&amp;gt;o, U+1EDC-&amp;gt;o, U+1EDD-&amp;gt;o, U+1EDE-&amp;gt;o, U+1EDF-&amp;gt;o, U+1EE0-&amp;gt;o, U+1EE1-&amp;gt;o, U+1EE2-&amp;gt;o, U+1EE3-&amp;gt;o, U+2092-&amp;gt;o, U+2C9E-&amp;gt;o, U+2C9F-&amp;gt;o, \
    U+01A4-&amp;gt;p, U+01A5-&amp;gt;p, U+1D18-&amp;gt;p, U+1D3E-&amp;gt;p, U+1D56-&amp;gt;p, U+1D71-&amp;gt;p, U+1D7D-&amp;gt;p, U+1D88-&amp;gt;p, U+1E54-&amp;gt;p, U+1E55-&amp;gt;p, U+1E56-&amp;gt;p, U+1E57-&amp;gt;p, U+2C63-&amp;gt;p, \
    U+024A-&amp;gt;q, U+024B-&amp;gt;q, U+02A0-&amp;gt;q, \
    U+0154-&amp;gt;r, U+0155-&amp;gt;r, U+0156-&amp;gt;r, U+0157-&amp;gt;r, U+0158-&amp;gt;r, U+0159-&amp;gt;r, U+0210-&amp;gt;r, U+0211-&amp;gt;r, U+0212-&amp;gt;r, U+0213-&amp;gt;r, U+024C-&amp;gt;r, U+024D-&amp;gt;r, U+0279-&amp;gt;r, U+027A-&amp;gt;r, U+027B-&amp;gt;r, U+027C-&amp;gt;r, U+027D-&amp;gt;r, U+027E-&amp;gt;r, U+027F-&amp;gt;r, U+0280-&amp;gt;r, U+0281-&amp;gt;r, U+02B3-&amp;gt;r, U+02B4-&amp;gt;r, U+02B5-&amp;gt;r, U+02B6-&amp;gt;r, U+1D19-&amp;gt;r, U+1D1A-&amp;gt;r, U+1D3F-&amp;gt;r, U+1D63-&amp;gt;r, U+1D72-&amp;gt;r, U+1D73-&amp;gt;r, U+1D89-&amp;gt;r, U+1DCA-&amp;gt;r, U+1E58-&amp;gt;r, U+1E59-&amp;gt;r, U+1E5A-&amp;gt;r, U+1E5B-&amp;gt;r, U+1E5C-&amp;gt;r, U+1E5D-&amp;gt;r, U+1E5E-&amp;gt;r, U+1E5F-&amp;gt;r, U+211C-&amp;gt;r, U+2C64-&amp;gt;r, \
    U+00DF-&amp;gt;s, U+015A-&amp;gt;s, U+015B-&amp;gt;s, U+015C-&amp;gt;s, U+015D-&amp;gt;s, U+015E-&amp;gt;s, U+015F-&amp;gt;s, U+0160-&amp;gt;s, U+0161-&amp;gt;s, U+017F-&amp;gt;s, U+0218-&amp;gt;s, U+0219-&amp;gt;s, U+023F-&amp;gt;s, U+0282-&amp;gt;s, U+02E2-&amp;gt;s, U+1D74-&amp;gt;s, U+1D8A-&amp;gt;s, U+1DB3-&amp;gt;s, U+1E60-&amp;gt;s, U+1E61-&amp;gt;s, U+1E62-&amp;gt;s, U+1E63-&amp;gt;s, U+1E64-&amp;gt;s, U+1E65-&amp;gt;s, U+1E66-&amp;gt;s, U+1E67-&amp;gt;s, U+1E68-&amp;gt;s, U+1E69-&amp;gt;s, U+1E9B-&amp;gt;s, \
    U+0162-&amp;gt;t, U+0163-&amp;gt;t, U+0164-&amp;gt;t, U+0165-&amp;gt;t, U+0166-&amp;gt;t, U+0167-&amp;gt;t, U+01AB-&amp;gt;t, U+01AC-&amp;gt;t, U+01AD-&amp;gt;t, U+01AE-&amp;gt;t, U+021A-&amp;gt;t, U+021B-&amp;gt;t, U+0236-&amp;gt;t, U+023E-&amp;gt;t, U+0287-&amp;gt;t, U+0288-&amp;gt;t, U+1D1B-&amp;gt;t, U+1D40-&amp;gt;t, U+1D57-&amp;gt;t, U+1D75-&amp;gt;t, U+1DB5-&amp;gt;t, U+1E6A-&amp;gt;t, U+1E6B-&amp;gt;t, U+1E6C-&amp;gt;t, U+1E6D-&amp;gt;t, U+1E6E-&amp;gt;t, U+1E6F-&amp;gt;t, U+1E70-&amp;gt;t, U+1E71-&amp;gt;t, U+1E97-&amp;gt;t, U+2C66-&amp;gt;t, \
    U+00D9-&amp;gt;u, U+00DA-&amp;gt;u, U+00DB-&amp;gt;u, U+00DC-&amp;gt;u, U+00F9-&amp;gt;u, U+00FA-&amp;gt;u, U+00FB-&amp;gt;u, U+00FC-&amp;gt;u, U+010316-&amp;gt;u, U+0168-&amp;gt;u, U+0169-&amp;gt;u, U+016A-&amp;gt;u, U+016B-&amp;gt;u, U+016C-&amp;gt;u, U+016D-&amp;gt;u, U+016E-&amp;gt;u, U+016F-&amp;gt;u, U+0170-&amp;gt;u, U+0171-&amp;gt;u, U+0172-&amp;gt;u, U+0173-&amp;gt;u, U+01AF-&amp;gt;u, U+01B0-&amp;gt;u, U+01D3-&amp;gt;u, U+01D4-&amp;gt;u, U+01D5-&amp;gt;u, U+01D6-&amp;gt;u, U+01D7-&amp;gt;u, U+01D8-&amp;gt;u, U+01D9-&amp;gt;u, U+01DA-&amp;gt;u, U+01DB-&amp;gt;u, U+01DC-&amp;gt;u, U+0214-&amp;gt;u, U+0215-&amp;gt;u, U+0216-&amp;gt;u, U+0217-&amp;gt;u, U+0244-&amp;gt;u, U+0289-&amp;gt;u, U+1D1C-&amp;gt;u, U+1D1D-&amp;gt;u, U+1D1E-&amp;gt;u, U+1D41-&amp;gt;u, U+1D58-&amp;gt;u, U+1D59-&amp;gt;u, U+1D64-&amp;gt;u, U+1D7E-&amp;gt;u, U+1D99-&amp;gt;u, U+1DB6-&amp;gt;u, U+1DB8-&amp;gt;u, U+1E72-&amp;gt;u, U+1E73-&amp;gt;u, U+1E74-&amp;gt;u, U+1E75-&amp;gt;u, U+1E76-&amp;gt;u, U+1E77-&amp;gt;u, U+1E78-&amp;gt;u, U+1E79-&amp;gt;u, U+1E7A-&amp;gt;u, U+1E7B-&amp;gt;u, U+1EE4-&amp;gt;u, U+1EE5-&amp;gt;u, U+1EE6-&amp;gt;u, U+1EE7-&amp;gt;u, U+1EE8-&amp;gt;u, U+1EE9-&amp;gt;u, U+1EEA-&amp;gt;u, U+1EEB-&amp;gt;u, U+1EEC-&amp;gt;u, U+1EED-&amp;gt;u, U+1EEE-&amp;gt;u, U+1EEF-&amp;gt;u, U+1EF0-&amp;gt;u, U+1EF1-&amp;gt;u, \
    U+01B2-&amp;gt;v, U+0245-&amp;gt;v, U+028B-&amp;gt;v, U+028C-&amp;gt;v, U+1D20-&amp;gt;v, U+1D5B-&amp;gt;v, U+1D65-&amp;gt;v, U+1D8C-&amp;gt;v, U+1DB9-&amp;gt;v, U+1DBA-&amp;gt;v, U+1E7C-&amp;gt;v, U+1E7D-&amp;gt;v, U+1E7E-&amp;gt;v, U+1E7F-&amp;gt;v, U+2C74-&amp;gt;v, \
    U+0174-&amp;gt;w, U+0175-&amp;gt;w, U+028D-&amp;gt;w, U+02B7-&amp;gt;w, U+1D21-&amp;gt;w, U+1D42-&amp;gt;w, U+1E80-&amp;gt;w, U+1E81-&amp;gt;w, U+1E82-&amp;gt;w, U+1E83-&amp;gt;w, U+1E84-&amp;gt;w, U+1E85-&amp;gt;w, U+1E86-&amp;gt;w, U+1E87-&amp;gt;w, U+1E88-&amp;gt;w, U+1E89-&amp;gt;w, U+1E98-&amp;gt;w, \
    U+02E3-&amp;gt;x, U+1D8D-&amp;gt;x, U+1E8A-&amp;gt;x, U+1E8B-&amp;gt;x, U+1E8C-&amp;gt;x, U+1E8D-&amp;gt;x, U+2093-&amp;gt;x, \
    U+00DD-&amp;gt;y, U+00FD-&amp;gt;y, U+00FF-&amp;gt;y, U+0176-&amp;gt;y, U+0177-&amp;gt;y, U+0178-&amp;gt;y, U+01B3-&amp;gt;y, U+01B4-&amp;gt;y, U+0232-&amp;gt;y, U+0233-&amp;gt;y, U+024E-&amp;gt;y, U+024F-&amp;gt;y, U+028E-&amp;gt;y, U+028F-&amp;gt;y, U+02B8-&amp;gt;y, U+1E8E-&amp;gt;y, U+1E8F-&amp;gt;y, U+1E99-&amp;gt;y, U+1EF2-&amp;gt;y, U+1EF3-&amp;gt;y, U+1EF4-&amp;gt;y, U+1EF5-&amp;gt;y, U+1EF6-&amp;gt;y, U+1EF7-&amp;gt;y, U+1EF8-&amp;gt;y, U+1EF9-&amp;gt;y, \
    U+0179-&amp;gt;z, U+017A-&amp;gt;z, U+017B-&amp;gt;z, U+017C-&amp;gt;z, U+017D-&amp;gt;z, U+017E-&amp;gt;z, U+01B5-&amp;gt;z, U+01B6-&amp;gt;z, U+0224-&amp;gt;z, U+0225-&amp;gt;z, U+0240-&amp;gt;z, U+0290-&amp;gt;z, U+0291-&amp;gt;z, U+1D22-&amp;gt;z, U+1D76-&amp;gt;z, U+1D8E-&amp;gt;z, U+1DBB-&amp;gt;z, U+1DBC-&amp;gt;z, U+1DBD-&amp;gt;z, U+1E90-&amp;gt;z, U+1E91-&amp;gt;z, U+1E92-&amp;gt;z, U+1E93-&amp;gt;z, U+1E94-&amp;gt;z, U+1E95-&amp;gt;z, U+2128-&amp;gt;z, U+2C6B-&amp;gt;z, U+2C6C-&amp;gt;z, \
    U+00C6-&amp;gt;U+00E6, U+01E2-&amp;gt;U+00E6, U+01E3-&amp;gt;U+00E6, U+01FC-&amp;gt;U+00E6, U+01FD-&amp;gt;U+00E6, U+1D01-&amp;gt;U+00E6, U+1D02-&amp;gt;U+00E6, U+1D2D-&amp;gt;U+00E6, U+1D46-&amp;gt;U+00E6, U+00E6
&lt;/code&gt;&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/darwinweb/~4/6dXaKIUxx4k" height="1" width="1"/&gt;</description>
      <author>Gabe da Silveira</author>
      <pubDate>Fri, 01 May 2009 20:24:00 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/darwinweb/~3/6dXaKIUxx4k/thinking_sphinx_case_folding_configuration</link>
      <guid isPermaLink="false">http://darwinweb.net/article/thinking_sphinx_case_folding_configuration</guid>
    <feedburner:origLink>http://darwinweb.net/article/thinking_sphinx_case_folding_configuration</feedburner:origLink></item>
    <item>
      <title>Ruby Time Tracker</title>
      <description>&lt;p&gt;There&amp;#8217;s a lot of time tracking software out there.  Web-based, commercial and shareware.  I found one desktop time tracker that cost $50 and that&amp;#8217;s all it does!   In reality the most efficient system I&amp;#8217;ve ever used is writing down times and tasks on paper.  However maybe a little automation is in order.  Here&amp;#8217;s a script I wrote in 20 minutes (maybe 21 minutes, but it wasn&amp;#8217;t done yet so I can&amp;#8217;t be sure).  It does what I need, which isn&amp;#8217;t much.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
def format_seconds(seconds)
  seconds = seconds.to_i
  minutes = seconds / 60
  seconds = seconds % 60
  hours = minutes / 60
  minutes = minutes % 60
  sprintf("%2d:%02d:%02d", hours, minutes, seconds)
end

puts "=== Time Tracker ==="
print "What are you working on? "
input = task_name = $stdin.readline.chomp
start_time = Time.now
tasks = []
intermediate_seconds = 0
while input != ''
  print "Enter new task (or 'pause', return to quit): "
  input = $stdin.readline.chomp
  if input == 'pause'
    pause_time = Time.now
    print "(Paused, hit any key to resume)"
    $stdin.readline.chomp
    intermediate_seconds += pause_time - start_time
    start_time = Time.now
  else
    intermediate_seconds += Time.now - start_time
    tasks &amp;lt;&amp;lt; format_seconds(intermediate_seconds) + " " + task_name + " (" + Time.now.strftime('%b %d %H:%M') + ")"
    intermediate_seconds = 0
    start_time = Time.now
    task_name = input
  end
end

puts tasks
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Geez I need a syntax highlighter on here.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/darwinweb/~4/uMWZxN2eb5E" height="1" width="1"/&gt;</description>
      <author>Gabe da Silveira</author>
      <pubDate>Sat, 08 Nov 2008 20:38:00 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/darwinweb/~3/uMWZxN2eb5E/ruby_time_tracker</link>
      <guid isPermaLink="false">http://darwinweb.net/article/ruby_time_tracker</guid>
    <feedburner:origLink>http://darwinweb.net/article/ruby_time_tracker</feedburner:origLink></item>
    <item>
      <title>AttachmentFu Pull S3 From Production Bucket While Developing</title>
      <description>&lt;p&gt;Populating a database is a chore.  As soon as a project gets deployed and the prospective admins are swarming about inputting data, my routine of downloading the production database chock-full of tasty data begins.  During development most of my data was actually produced in production.&lt;/p&gt;
&lt;p&gt;Normally this is a seamless process automated by a cut and paste snippet.  But with AttachmentFu using the S3 backend, the bucket where files are stored is implict based on the configuration for your particular environment.  There are a few potential solutions:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;Share buckets between environments.&lt;/strong&gt;  This is the easiest, but also quite risky with regards to data integrity&amp;#8212;if you follow a policy of only deleting attachments from the primary environment this can work, however there is still a slight risk of overwriting data with the same name.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Copy data between buckets.&lt;/strong&gt; This is sort of a pain.  The logic can be quite simple though, and if you have an EC2 instance set up it is pretty fast.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Hack the &lt;span class="caps"&gt;URL&lt;/span&gt;.&lt;/strong&gt; The quick and dirty, but effective solution is to hack the URLs that are output to the browser so you can view the images from an alternate bucket without affecting uploads or deletions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I want to do this locally without modifying the repository code, so what I did is add a new file containing the following to &lt;code&gt;config/initializers/&lt;/code&gt; and add it to my local git ignores:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
Technoweenie::AttachmentFu::Backends::S3Backend.module_eval do
  def s3_url(thumbnail = nil)
    File.join(s3_protocol + s3_hostname + s3_port_string, 'production_bucket', full_filename(thumbnail))
  end
  alias :public_filename :s3_url
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The downside is that you won&amp;#8217;t be able to see files that were uploaded from development.  But for me that doesn&amp;#8217;t matter because I only ever do that when I&amp;#8217;m developing the image uploading forms, which soon are overwritten by production data.&lt;/p&gt;
&lt;p&gt;Implementing this for secure urls is left as an exercise to the reader.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/darwinweb/~4/apsJoTYBHBE" height="1" width="1"/&gt;</description>
      <author>Gabe da Silveira</author>
      <pubDate>Sat, 30 Aug 2008 16:38:00 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/darwinweb/~3/apsJoTYBHBE/attachmentfu_pull_s3_from_production_bucket_while_developing</link>
      <guid isPermaLink="false">http://darwinweb.net/article/attachmentfu_pull_s3_from_production_bucket_while_developing</guid>
    <feedburner:origLink>http://darwinweb.net/article/attachmentfu_pull_s3_from_production_bucket_while_developing</feedburner:origLink></item>
    <item>
      <title>Specifying an Explicit ActiveRecord Version in Merb</title>
      <description>&lt;p&gt;Last night, I needed to make a quick update to my merb app&amp;#8217;s schema.  Nothing fancy.  This is my first update since Rails 2.1 dropped with it&amp;#8217;s improved migration naming scheme.  For whatever reason &lt;code&gt;rake db:migrate&lt;/code&gt; did not work as smoothly as it did in Rails.  Since I was on a short deadline I decided to revert to ActiveRecord 2.0.2 rather than debug the actual problem.  I figured this ought to be pretty trivial right?&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m still very much a Merb newbie, but it wasn&amp;#8217;t too hard to figure out to put this in my &lt;code&gt;init.rb&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
dependency "activerecord", "= 2.0.2"
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As long as it appears before the &lt;code&gt;use_orm&lt;/code&gt; line it does what it&amp;#8217;s supposed to.  Well, at least it does when you run merb start.  However my problem was with &lt;code&gt;rake db:migrate&lt;/code&gt; which now had a new problem:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
can't activate activesupport (= 2.0.2), already activated activesupport-2.1.0]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I tried several solutions including requiring activesupport 2.0.2 explicitly and installing the specific gems into &lt;code&gt;./gems&lt;/code&gt;.  Same problem.  Obviously there was a problem before the Merb invocation.  Turns out the &lt;code&gt;Rakefile&lt;/code&gt; requires &lt;code&gt;rubigen&lt;/code&gt; which in turn requires &lt;code&gt;activesupport&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Okay, no big deal, just add this somewhere above &lt;code&gt;rubigen&lt;/code&gt; in the &lt;code&gt;Rakefile&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
gem "activesupport", "= 2.0.2"
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the Merb app and rake tasks work, but a quick test reveals &lt;code&gt;merb-gen&lt;/code&gt; is now borked same as &lt;code&gt;rake&lt;/code&gt; was.  Same error, same cause.  Problem is &lt;code&gt;ActiveSupport&lt;/code&gt; is required in the very first file which is part of the official release at &lt;code&gt;/usr/local/bin/merb-gen&lt;/code&gt;.  So to actually solve this problem you need to specify the &lt;code&gt;ActiveSupport&lt;/code&gt; version in that executable file.&lt;/p&gt;
&lt;p&gt;At this point I&amp;#8217;m starting to think I should have debugged the original problem and submitted a patch to fix it, but I&amp;#8217;ve got a working fix which is what I need right now, so I duplicate the file into my working directory and add the fix.&lt;/p&gt;
&lt;p&gt;All this has me reflecting on the difficulties of dependency management, and the value of stable public interfaces.  The general case seems very hard to manage, but I can think of some solutions at the Merb level.  Hmm, maybe my first Merb patch?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/darwinweb/~4/3VoYy7NQGic" height="1" width="1"/&gt;</description>
      <author>Gabe da Silveira</author>
      <pubDate>Sun, 22 Jun 2008 19:59:00 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/darwinweb/~3/3VoYy7NQGic/specifying_an_explicit_activerecord_version_in_merb</link>
      <guid isPermaLink="false">http://darwinweb.net/article/specifying_an_explicit_activerecord_version_in_merb</guid>
    <feedburner:origLink>http://darwinweb.net/article/specifying_an_explicit_activerecord_version_in_merb</feedburner:origLink></item>
    <item>
      <title>Rails 2.1 has_many :through Conditions Regression</title>
      <description>&lt;p&gt;Pulled our application up to Rails 2.1 yesterday.  This is the first major release since we moved off of edge as of Rails 2.0, so the set of &lt;a href="http://ryandaigle.com/articles/2008/6/2/rails-2-1-released-summary-of-features"&gt;major features&lt;/a&gt; is pretty exciting this time around.  One less visible change is &lt;a href="http://dev.rubyonrails.org/ticket/9640"&gt;a bunch of work&lt;/a&gt; optimizing the the &lt;code&gt;:include&lt;/code&gt; option, best explained by &lt;a href="http://www.akitaonrails.com/2008/5/26/rolling-with-rails-2-1-the-first-full-tutorial-part-2" title="see 2nd section"&gt;Fabio&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The first thing I want to say about this is that it&amp;#8217;s awesome.  The performance problems with either multiple includes or the infamous n + 1 problem were both potentially severe and fairly intractable.  The workarounds were not pretty.  That said, I think a fair number of people are going to experience breakage due to the fact that what used to be one query is now potentially multiple queries, and there&amp;#8217;s no good way for ActiveRecord to detect or fix what broke between 2.0 and 2.1.&lt;/p&gt;
&lt;p&gt;In our case we had one broken query which was remedied with the following advice.  I&amp;#8217;m addressing the specific case here, but it&amp;#8217;s just one very tiny edge case among a large set of tiny edge cases.&lt;/p&gt;
&lt;h2&gt;Don&amp;#8217;t Put Conditions Affecting the Join Tabled into has_many :through&lt;/h2&gt;
&lt;p&gt;Here&amp;#8217;s something which used to work that doesn&amp;#8217;t anymore:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
class Film &amp;lt; ActiveRecord::Base
  has_many :memberships
  has_many :directors, :through =&amp;gt; :memberships, :source =&amp;gt; :cast_member, :conditions =&amp;gt; "memberships.role = 'Director'"
end

Film.find(:all, :include =&amp;gt; :directors)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The problem here is that the memberships table is no longer available when it is loading the cast_members (directors), so the specified conditions throw a mysql error.&lt;/p&gt;
&lt;p&gt;I gave some thought to fixing this, but the solution would be worse than the problem.  Solving just the simple case would require passing around a lot of extra parameters and lists of tables.  Start considering compound conditions, variations in &lt;span class="caps"&gt;SQL&lt;/span&gt;, and proving correctness of the whole mess and you get some sense of why &lt;span class="caps"&gt;ORM&lt;/span&gt; is best kept simple and &lt;code&gt;find_by_sql&lt;/code&gt; is your friend.&lt;/p&gt;
&lt;p&gt;So instead I just did this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
has_many :directorships, :class_name =&amp;gt; "Membership", :conditions =&amp;gt; "role = 'Director'"
has_many :directors, :through =&amp;gt; :directorships, :source =&amp;gt; :cast_member
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The lesson here is that association conditions should only reference fields from the target table.  Maybe this was already obvious, but if you really need to depend on multiple tables then the &lt;code&gt;:finder_sql&lt;/code&gt; is the recommended solution.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/darwinweb/~4/dKD4RPSj19U" height="1" width="1"/&gt;</description>
      <author>Gabe da Silveira</author>
      <pubDate>Wed, 04 Jun 2008 04:33:00 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/darwinweb/~3/dKD4RPSj19U/rails_21_has_many_through_conditions_regression</link>
      <guid isPermaLink="false">http://darwinweb.net/article/rails_21_has_many_through_conditions_regression</guid>
    <feedburner:origLink>http://darwinweb.net/article/rails_21_has_many_through_conditions_regression</feedburner:origLink></item>
    <item>
      <title>Avoid Variable Collisions in Rails Controllers</title>
      <description>&lt;p&gt;Rails is by and large developer-friendly.  But when bugs do arise, they have the potential to be nasty&amp;#8212;at least until one becomes familiar with the techniques of Ruby debugging, which often require more subtlety than a less-dynamic language like Java or a language with more powerful introspection like Smalltalk.&lt;/p&gt;
&lt;p&gt;Over the past 3 years of intensive ruby programming, the most gut-wrenchingly bizarre bugs I&amp;#8217;ve encountered have usually had to do with name collisions. One reason is because Ruby allows opening of classes at will and because Rails is not warning-friendly (ie. Rails is not run with the &lt;code&gt;ruby -w&lt;/code&gt; flag), it&amp;#8217;s exceedingly easy to clobber existing functions to all manner of bizarre effect.  Keeping this potential in the back of one&amp;#8217;s mind makes problems 90% easier to deal with when they come, which in my experience is rare but regular.&lt;/p&gt;
&lt;p&gt;A simpler form of name collision occurs with instance variables, of which Rails uses a liberal sprinkling.  Now for a long time the official word has been to &lt;a href="http://weblog.rubyonrails.org/2006/4/25/use-params-not-params"&gt;avoid directly using instance variables provided by Rails&lt;/a&gt;, but the more important corollary has been neglected: &lt;strong&gt;Don&amp;#8217;t clobber Rails internal instance variables&lt;/strong&gt;.  This is probably something that warrants a section in the documentation.  For instance, setting any of these instance variables for application purposes is likely to cause problems:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;@url&lt;/li&gt;
	&lt;li&gt;@template&lt;/li&gt;
	&lt;li&gt;@assigns&lt;/li&gt;
	&lt;li&gt;@_session&lt;/li&gt;
	&lt;li&gt;@_request&lt;/li&gt;
	&lt;li&gt;@_params&lt;/li&gt;
	&lt;li&gt;@_cookies&lt;/li&gt;
	&lt;li&gt;@_response&lt;/li&gt;
	&lt;li&gt;@_headers&lt;/li&gt;
	&lt;li&gt;@controller_class_name&lt;/li&gt;
	&lt;li&gt;@controller_name&lt;/li&gt;
	&lt;li&gt;@controller_path&lt;/li&gt;
	&lt;li&gt;@view_paths&lt;/li&gt;
	&lt;li&gt;@performed_render&lt;/li&gt;
	&lt;li&gt;@performed_redirect&lt;/li&gt;
	&lt;li&gt;@action_name&lt;/li&gt;
	&lt;li&gt;@action_methods&lt;/li&gt;
	&lt;li&gt;@variables_added&lt;/li&gt;
	&lt;li&gt;@request_origin&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Keep in mind these are just the variables from the &lt;code&gt;ActionController::Base&lt;/code&gt; file, but there are other instance variables mixed in from the various ActionController components.  Some of these are more likely to be clobbered than others, but when you accidentally use one of them there&amp;#8217;s really no telling what will happen.  I used @url in a production project &lt;em&gt;months&lt;/em&gt; ago, and only discovered the problem when I added an explicit query string parameter to a named url helper in my project&amp;#8217;s layout, resulting in deep and somewhat perplexing breakage.&lt;/p&gt;
&lt;p&gt;Clearly this situation could be improved at the framework level in a variety of ways, but I&amp;#8217;ll stop short of recommending a solution.  Simply being aware of the issue can save a lot of costly debugging time, so this note is here as a reminder to myself and others.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/darwinweb/~4/l5OQbuVReSM" height="1" width="1"/&gt;</description>
      <author>Gabe da Silveira</author>
      <pubDate>Thu, 10 Apr 2008 07:14:00 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/darwinweb/~3/l5OQbuVReSM/avoid_variable_collisions_in_rails_controllers</link>
      <guid isPermaLink="false">http://darwinweb.net/article/avoid_variable_collisions_in_rails_controllers</guid>
    <feedburner:origLink>http://darwinweb.net/article/avoid_variable_collisions_in_rails_controllers</feedburner:origLink></item>
    <item>
      <title>Rails Multisite Plugin Ready For Prime Time</title>
      <description>&lt;p&gt;For those of you who were following my &lt;a href="http://code.google.com/p/rails-multisite/"&gt;multisite plugin&lt;/a&gt;, be aware that it is now updated and ready for use in Rails 2.0.2.&lt;/p&gt;
&lt;p&gt;See he &lt;a href="http://darwinweb.net/articles/56-announcing_multisite_plugin_for_rails"&gt;original announcement&lt;/a&gt; for more information about its use.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s worth noting that this plugin conflicts with all template caching.  You will get an exception if you try to use it with template caching.  I believe caching can be supported fairly easily with some small monkey patches to Rails.  That may be forthcoming if there is demand for it (I don&amp;#8217;t need it yet myself).&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/darwinweb/~4/--B2VB2UGPQ" height="1" width="1"/&gt;</description>
      <author>Gabe da Silveira</author>
      <pubDate>Mon, 25 Feb 2008 20:22:00 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/darwinweb/~3/--B2VB2UGPQ/rails_multisite_plugin_ready_for_prime_time</link>
      <guid isPermaLink="false">http://darwinweb.net/article/rails_multisite_plugin_ready_for_prime_time</guid>
    <feedburner:origLink>http://darwinweb.net/article/rails_multisite_plugin_ready_for_prime_time</feedburner:origLink></item>
    <item>
      <title>Cookie Session Store for Facebook Applications</title>
      <description>&lt;p&gt;I was recently recruited to build a &lt;a href="http://facebook.com"&gt;facebook&lt;/a&gt; application on top of an existing Rails codebase running on edge.  Having been on edge with my previous project for at least 6 months, I&amp;#8217;ve gotten used to all the Rails 2.0 goodness.&lt;/p&gt;
&lt;p&gt;One of my favorite features is the &lt;a href="http://ryandaigle.com/articles/2007/2/21/what-s-new-in-edge-rails-cookie-based-sessions"&gt;cookie session store&lt;/a&gt; which is a huge slam dunk for scalability and general maintainenance&amp;#8212;that is to say, &lt;em&gt;no&lt;/em&gt; maintenance.&lt;/p&gt;
&lt;p&gt;Unfortunately facebook does not store cookies (as far as I can tell), and there is really no documentation of this to speak of out there on the web.  If you are using the cookie session store, nothing blows up, you just don&amp;#8217;t have a session.  It&amp;#8217;s pretty obvious when you think about it, but I spent a couple hours figuring out why my flash messages weren&amp;#8217;t coming through.  If this post saves one person 20 minutes, then it was time well spent.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/darwinweb/~4/dT4vBCk5Xas" height="1" width="1"/&gt;</description>
      <author>Gabe da Silveira</author>
      <pubDate>Tue, 23 Oct 2007 19:15:00 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/darwinweb/~3/dT4vBCk5Xas/cookie_session_store_for_facebook_applications</link>
      <guid isPermaLink="false">http://darwinweb.net/article/cookie_session_store_for_facebook_applications</guid>
    <feedburner:origLink>http://darwinweb.net/article/cookie_session_store_for_facebook_applications</feedburner:origLink></item>
    <item>
      <title>Bad Code</title>
      <description>&lt;p&gt;I caught up with &lt;a href="http://discuss.joelonsoftware.com/default.asp?joel.3.547336"&gt;this thread&lt;/a&gt; on Joel&amp;#8217;s discussion board today.  We software developers will take any opportunity to rant about the bass-ackwards code we have to deal with on a regular basis.  For passionate developers, it&amp;#8217;s understandable that most code wouldn&amp;#8217;t live up to our standards—only a select few projects have the amount of resources necessary to truly pursue perfection.  Over time the exposure to imperfect code can condition us with unfair knee-jerk reaction to new code.&lt;/p&gt;
&lt;h2&gt;How bad is the code really?&lt;/h2&gt;
&lt;p&gt;The world is full of terrible code.  Usually that becomes painfully obvious at maintenance time.  When an existing project is opened up for the first time by a new team member, I think the instinct is to see the flaws before the brilliance.  What kinds of things make code stinky?  Well it depends who you ask, but some possible reasons are:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Unnecessary duplication of code (under-abstracted)&lt;/li&gt;
	&lt;li&gt;Overly complicated code (over-abstracted or unnecessarily clever)&lt;/li&gt;
	&lt;li&gt;Too many files/classes&lt;/li&gt;
	&lt;li&gt;Giant monolithic classes&lt;/li&gt;
	&lt;li&gt;Wrong design patterns applied&lt;/li&gt;
	&lt;li&gt;Stupid algorithms&lt;/li&gt;
	&lt;li&gt;Failure to use appropriate libraries or framework features (reinventing the wheel)&lt;/li&gt;
	&lt;li&gt;Inconsistency (lack of conventions)&lt;/li&gt;
	&lt;li&gt;Numerous obvious comments&lt;/li&gt;
	&lt;li&gt;No documentation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Anyone whose done their share of code maintenance has probably been annoyed by most of the things on this list one time or another.  &amp;#8220;&lt;em&gt;If only they had done it &lt;strong&gt;this&lt;/strong&gt; way&lt;/em&gt;.&amp;#8221;  It&amp;#8217;s easy to just assume the code sucks based on a first impression.  Once you jump to that conclusion, every minor flaw affirms your prejudice.&lt;/p&gt;
&lt;h2&gt;Pet peeves&lt;/h2&gt;
&lt;p&gt;Let&amp;#8217;s step back a minute and give ourselves an ego check.  To an experienced developer there are hundreds of nuances that will stick out like a sore thumb, but they are likely to annoy you far more than they actually impact your productivity were you to consider them objectively.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re not careful, your concern for the code boils over into judgement of the previous programmers.  Maybe the last guy wasn&amp;#8217;t up to snuff in this language, maybe his pet peeves were different, maybe he was just a blathering idiot.  Whatever the case, why dwell on it?&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve managed to make it through a lot of bad code without slowing down much.  Every once and a while a refactoring or straight-up delete and rewrite was necessary, but most of the time I was able to grit my teeth and get some changes done relatively quickly.&lt;/p&gt;
&lt;h2&gt;Real reasons code &amp;#8220;sucks&amp;#8221;&lt;/h2&gt;
&lt;p&gt;The problem facing you is likely to be different from what the last programmer faced.  It would be foolish to assume that the software was designed with the same requirements that you have in front of you today.  Who&amp;#8217;s to say the business goals haven&amp;#8217;t changed drastically since then?&lt;/p&gt;
&lt;p&gt;You and the last developer have different information.  Even after you&amp;#8217;ve spent a lot of time on the code and understand all the intricacies and business goals, you still may not know the history of the project.  Maybe the code has grown and shrunk and morphed into something completely different from when it started.  If it&amp;#8217;s time to refactor, maybe that&amp;#8217;s &lt;em&gt;your&lt;/em&gt; job.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s also quite possible that refactoring is not worth it.  Good developers innately want maintainable and aesthetically pleasing code, but there is a cost.  We can&amp;#8217;t write perfect software before we understand it, and we can&amp;#8217;t refactor without spending time.  The developer is usually in a better position than the manager to assess the long-term cost of &lt;em&gt;not&lt;/em&gt; refactoring, but he also has a vested interested in exaggerating that cost.  To make a fair assessment, the developer &lt;em&gt;must&lt;/em&gt; have a direct business interest.  Even then there&amp;#8217;s a great deal of uncertainty.  It&amp;#8217;s always a gamble.&lt;/p&gt;
&lt;h2&gt;Cognitive dissonance&lt;/h2&gt;
&lt;p&gt;Developers are conditioned to be right.  Our job requires a fiercely logical thought process and the ability to make absolute assertions.  Being wrong means things are broken, sometimes spectacularly so.  And because we think so hard about things in this way, our conclusions are usually well-reasoned.  But we are still human, and we still have the same defense mechanisms around our belief systems as everybody else.  The insidious thing is that our reasoning blinds us to our own subjectivity.  Our open-mindedness is a badge of pride, but also a set of  subconscious blinders.&lt;/p&gt;
&lt;p&gt;The only really objective thing about software is its output.&lt;/p&gt;
&lt;p&gt;Software engineering is about making choices.  Some choices are pragmatic (C++ for performance), some are philosophical (Ruby vs Python), but most are an intangible mixture of past experience and future expectations.  When you see some code for the first time, the chances that it will mesh with your experience and philosophy are pretty slim.  Eventually you may come to appreciate it for what it is, but in the meantime every tradeoff that didn&amp;#8217;t follow your current line of thought will irk you.&lt;/p&gt;
&lt;h2&gt;Software is messy&lt;/h2&gt;
&lt;p&gt;None of this is to say that there aren&amp;#8217;t real quality problems in the software industry—of course there are.  But I think it&amp;#8217;s worth carefully considering our own motivations and biases before judging how bad the problem really is.&lt;/p&gt;
&lt;p&gt;We may not like dealing with inadequately-funded &lt;a href="http://www.laputan.org/mud/"&gt;balls of mud&lt;/a&gt;, but that&amp;#8217;s probably where most of the paying work is.  Even in relatively clean code bases, reasonable people can disagree on style or architecture points.  Regardless of initial code quality, there will always be difficult and inelegant maintenance that needs to be done.  My goal is to keep emotion out of it, and just fix problems.  Refactoring is great if a business case can be made, otherwise just slog through as fast as possible without complaining.&lt;/p&gt;
&lt;p&gt;Easier said than done, I know.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/darwinweb/~4/0hjcP-PziXA" height="1" width="1"/&gt;</description>
      <author>Gabe da Silveira</author>
      <pubDate>Mon, 01 Oct 2007 23:07:00 +0000</pubDate>
      <link>http://feedproxy.google.com/~r/darwinweb/~3/0hjcP-PziXA/bad_code</link>
      <guid isPermaLink="false">http://darwinweb.net/article/bad_code</guid>
    <feedburner:origLink>http://darwinweb.net/article/bad_code</feedburner:origLink></item>
  </channel>
</rss>
