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

<channel>
	<title>7fff &#187; Rails</title>
	<atom:link href="http://7fff.com/category/rails/feed/" rel="self" type="application/rss+xml" />
	<link>http://7fff.com</link>
	<description></description>
	<lastBuildDate>Fri, 30 Dec 2011 21:03:10 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Rails 3.0 to 3.1 gotcha: Changed ActiveSupport::JSON.backend</title>
		<link>http://7fff.com/2011/10/06/rails-3-0-to-3-1-gotcha-changed-activesupportjson-backend/</link>
		<comments>http://7fff.com/2011/10/06/rails-3-0-to-3-1-gotcha-changed-activesupportjson-backend/#comments</comments>
		<pubDate>Thu, 06 Oct 2011 18:10:02 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://7fff.com/?p=669</guid>
		<description><![CDATA[Ow.
In Rails 3.0, the default ActiveSupport::JSON backend is YAML.
In Rails 3.1, it&#8217;s YAJL.
They deserialize JSON times differently. In 3.0 . . .


ruby-1.9.2-p290 :001 &#62; ActiveSupport::JSON.decode( '{&#34;at&#34;: &#34;2011-10-13T12:00:00+00:00&#34;}' )
 =&#62; {&#34;at&#34;=&#62;2011-10-13 07:00:00 -0500} 

See the lack of quotation marks around what &#8220;at&#8221; points to? It&#8217;s not a String. YAML converts the value to an actual DateTime. [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>Ow.</p>
<p>In Rails 3.0, the default ActiveSupport::JSON backend is YAML.</p>
<p>In Rails 3.1, it&#8217;s YAJL.</p>
<p>They deserialize JSON times differently. In 3.0 . . .</p>
<pre name="code" class="ruby">

ruby-1.9.2-p290 :001 &gt; ActiveSupport::JSON.decode( '{&quot;at&quot;: &quot;2011-10-13T12:00:00+00:00&quot;}' )
 =&gt; {&quot;at&quot;=&gt;2011-10-13 07:00:00 -0500} 
</pre>
<p>See the lack of quotation marks around what &#8220;at&#8221; points to? It&#8217;s not a String. YAML converts the value to an actual DateTime. (There a DATE_REGEX defined in ActiveSupport::JSON that does the matching.</p>
<p>But in 3.1:</p>
<pre name="code" class="ruby">

ruby-1.9.2-p290 :001 &gt; ActiveSupport::JSON.decode( '{&quot;at&quot;: &quot;2011-10-13T12:00:00+00:00&quot;}' )
 =&gt; {&quot;at&quot;=&gt;&quot;2011-10-13T12:00:00+00:00&quot;} 
</pre>
<p>We had the yajl-ruby gem installed for development, so were getting the the Strings. Then on our staging server, we were getting the already-parsed time value, and were getting errors.</p>
<p>This strikes me as a substantive change. I&#8217;m not sure I&#8217;d call it a bug, but it was unexpected.</p>
]]></content:encoded>
			<wfw:commentRss>http://7fff.com/2011/10/06/rails-3-0-to-3-1-gotcha-changed-activesupportjson-backend/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Helpful Rails book: Rails AntiPatterns, by Pytel and Saleh</title>
		<link>http://7fff.com/2011/05/24/helpful-rails-book-rails-antipatterns-by-pytel-and-saleh/</link>
		<comments>http://7fff.com/2011/05/24/helpful-rails-book-rails-antipatterns-by-pytel-and-saleh/#comments</comments>
		<pubDate>Wed, 25 May 2011 00:33:48 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Reading]]></category>
		<category><![CDATA[Reviews]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://7fff.com/?p=600</guid>
		<description><![CDATA[So I&#8217;m reading Chad Pytel and Tammer Saleh&#8217;s book Rails AntiPatterns: Best Practice Ruby on Rails Refactoring, and it&#8217;s a good one. Oops, but I got the title wrong: It&#8217;s RailsTM AntiPatterns: Best Practice Ruby on RailsTM Refactoring. (I don&#8217;t want to get sued for leaving out those TMs.)
I&#8217;ve been writing RailsTM code for a [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>So I&#8217;m reading Chad Pytel and Tammer Saleh&#8217;s book <a href="http://www.amazon.com/gp/product/0321604814/ref=as_li_ss_tl?ie=UTF8&#038;tag=ce1-20&#038;linkCode=as2&#038;camp=217145&#038;creative=399349&#038;creativeASIN=0321604814">Rails AntiPatterns: Best Practice Ruby on Rails Refactoring</a>, and it&#8217;s a good one. Oops, but I got the title wrong: It&#8217;s <em>Rails<sup>TM</sup> AntiPatterns: Best Practice Ruby on Rails<sup>TM</sup> Refactoring</em>. (I don&#8217;t want to get sued for leaving out those TMs.)</p>
<p>I&#8217;ve been writing Rails<sup>TM</sup> code for a long time, and this book is embarrassing to read. Honestly, after reading a couple of chapters I cranked up my editor and made some tweaks to my code. Whew. Truly, this book has the goods on any number of things <em>you&#8217;re doing wrong</em> with your Rails<sup>TM</sup> app, and I would advise you to take seriously their advice.</p>
<p>There are chapters that teach things you should already know (on Models, Views, and Controllers), but also chapters that go beyond (those on using third-party code and services), and some where I think these guys know more than just about anyone (the chapter on testing). I kinda wish the testing chapter didn&#8217;t use Shoulda, but I guess it&#8217;s OK, since they invented it.</p>
<p>It&#8217;s hard to find things to gripe about. One oddity is that they recommend HTTP 401 for application-level (i.e., controller) authorization errors (p. 205): But I thought 401 was reserved for specifically HTTP-related auth (e.g., basic or digest &#8211; see the <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html">RFC</a>). I guess you can use it like this. They also talk about denormalization, and replacing joins with column constants (pp. 79-82). I guess so. (To be sure, they say that if there&#8217;s going to be a UI, you do want the table.) I think increasingly we need to look at our schemas as though a non-Rails application will be using it, sooner rather than later: In which case, such constants really do need to be in a separate table, even if there is no UI. So I would advocate sucking in a table with the right codes, putting the key values into the table, and just leaving out the association if you want to avoid the joins. Also in this area, they put their constant values into an Array (p. 81). Dudes, use a Set. Please.</p>
<p>These manufactured gripes aside, it&#8217;s a lovely book. Now let me get back to my editor and my Rails<sup>TM</sup> app so I can remove some more embarrassments. Sheesh, Law of Demeter AGAIN!?</p>
]]></content:encoded>
			<wfw:commentRss>http://7fff.com/2011/05/24/helpful-rails-book-rails-antipatterns-by-pytel-and-saleh/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Setting expires headers via Rack</title>
		<link>http://7fff.com/2011/03/25/setting-expires-headers-via-rack/</link>
		<comments>http://7fff.com/2011/03/25/setting-expires-headers-via-rack/#comments</comments>
		<pubDate>Fri, 25 Mar 2011 14:20:45 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://7fff.com/?p=593</guid>
		<description><![CDATA[For future reference:
To set expires headers on responses coming from your /assets path:
Add rack-contrib to your Gemfile
In config.ru, before your &#8220;run&#8221;:


require 'rack/contrib'
use Rack::StaticCache, :urls =&#62; [ '/assets', '/images', '/javascripts' ], :root =&#62; 'public'

The default is one year. For two, add :duration => 2 after the :urls specification.
That is all.
]]></description>
			<content:encoded><![CDATA[<p></p><p>For future reference:</p>
<p>To set expires headers on responses coming from your /assets path:</p>
<p>Add rack-contrib to your Gemfile</p>
<p>In config.ru, before your &#8220;run&#8221;:</p>
<pre name="code" class="ruby">

require 'rack/contrib'
use Rack::StaticCache, :urls =&gt; [ '/assets', '/images', '/javascripts' ], :root =&gt; 'public'
</pre>
<p>The default is one year. For two, add :duration => 2 after the :urls specification.</p>
<p>That is all.</p>
]]></content:encoded>
			<wfw:commentRss>http://7fff.com/2011/03/25/setting-expires-headers-via-rack/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Faster Net::HTTP for Ruby 1.8.6</title>
		<link>http://7fff.com/2008/12/20/faster-nethttp-for-ruby-186/</link>
		<comments>http://7fff.com/2008/12/20/faster-nethttp-for-ruby-186/#comments</comments>
		<pubDate>Sat, 20 Dec 2008 15:11:27 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://7fff.com/2008/12/20/faster-nethttp-for-ruby-186/</guid>
		<description><![CDATA[We&#8217;ve been a bit frustrated at work with Net::HTTP performance (as have so many others) so here&#8217;s a monkeypatch for 1.8.6 that combines the buffer size increase in 1.8.7 with Aaron Patterson&#8217;s recent tweak to use non-blocking IO (unfortunately, the non-blocking IO patch doesn&#8217;t work with HTTPS, which is why we use the buffer size [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>We&#8217;ve been a bit frustrated at work with Net::HTTP performance (<a href="http://apocryph.org/2008/11/09/more_indepth_analysis_ruby_http_client_performance/">as have so many others</a>) so here&#8217;s a monkeypatch for 1.8.6 that combines <a href="http://github.com/rubyspec/matzruby/commit/eeaf6f95d65041018916572971635b49d2f7ae52">the buffer size increase in 1.8.7</a> with <a href="http://redmine.ruby-lang.org/repositories/diff/ruby-19/lib/net/protocol.rb?rev=20443">Aaron Patterson&#8217;s recent tweak to use non-blocking IO</a> (unfortunately, the non-blocking IO patch doesn&#8217;t work with HTTPS, which is why we use the buffer size tweak when the @io variable suggests that HTTPS is happening. No guarantee implied, etc.</p>
<pre name="code" class="ruby">

class Net::BufferedIO #:nodoc:

  alias <img src='http://7fff.com/wp-includes/images/smilies/icon_surprised.gif' alt=':o' class='wp-smiley' /> ld_rbuf_fill :rbuf_fill

  def rbuf_fill

    BUFSIZE = 1024 * 16

    # HTTPS can't use the non-blocking strategy below in 1.8.6; so at least
    # increase buffer size over 1.8.6 default of 1024
    if !@io.respond_to? :read_nonblock
      timeout(@read_timeout) {
        @rbuf &lt;&lt; @io.sysread(BUFSIZE)
      }
      return
    end

    # non-blocking
    begin
      @rbuf &lt;&lt; @io.read_nonblock(BUFSIZE)
    rescue Errno::EWOULDBLOCK
      if IO.select([@io], nil, nil, @read_timeout)
        @rbuf &lt;&lt; @io.read_nonblock(BUFSIZE)
      else
        raise Timeout::TimeoutError
      end
    end

  end

end
</pre>
]]></content:encoded>
			<wfw:commentRss>http://7fff.com/2008/12/20/faster-nethttp-for-ruby-186/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Atrocious Rails API doc of the week</title>
		<link>http://7fff.com/2008/11/27/atrocious-rails-api-doc-of-the-week/</link>
		<comments>http://7fff.com/2008/11/27/atrocious-rails-api-doc-of-the-week/#comments</comments>
		<pubDate>Thu, 27 Nov 2008 01:16:00 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://7fff.com/2008/11/27/atrocious-rails-api-doc-of-the-week/</guid>
		<description><![CDATA[Here&#8217;s an example of some atrocious Rails API documentation.
(I say &#8220;of the week&#8221; which raised the question whether I could really find an atrocious Rails doc every week . . . but I probably can.)
Here&#8217;s the doc for the link_to helper:
http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#M001378
Notice that there is a heading &#8220;Options&#8221; describing keys such as :confirm, :popup, etc.
Well guess [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>Here&#8217;s an example of some atrocious Rails API documentation.</p>
<p>(I say &#8220;of the week&#8221; which raised the question whether I could really find an atrocious Rails doc every week . . . but I probably can.)</p>
<p>Here&#8217;s the doc for the link_to helper:</p>
<p><a href="http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#M001378">http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#M001378</a></p>
<p>Notice that there is a heading &#8220;Options&#8221; describing keys such as :confirm, :popup, etc.</p>
<p>Well guess what? Those Options are for the second Hash, i.e., html_options. How a newbie would ever figure this out is beyond me. I suppose you&#8217;re supposed to follow the link over to url_for and figure out that those options are for the first Hash . . . and then somehow that the &#8220;Options&#8221; given for link_to are for the 2nd Hash. One of my students in my Harvard Ruby/Rails course stumbled across this.</p>
]]></content:encoded>
			<wfw:commentRss>http://7fff.com/2008/11/27/atrocious-rails-api-doc-of-the-week/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Teaching Ruby and Ruby on Rails again at Harvard</title>
		<link>http://7fff.com/2008/08/07/teaching-ruby-and-ruby-on-rails-again-at-harvard/</link>
		<comments>http://7fff.com/2008/08/07/teaching-ruby-and-ruby-on-rails-again-at-harvard/#comments</comments>
		<pubDate>Thu, 07 Aug 2008 00:47:11 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Announcements]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://7fff.com/2008/08/07/teaching-ruby-and-ruby-on-rails-again-at-harvard/</guid>
		<description><![CDATA[Once again, I&#8217;m pleased to be offering a course on Ruby and Ruby on Rails at Harvard: course; course site.
We&#8217;ll try to avoid this anti-pattern:

]]></description>
			<content:encoded><![CDATA[<p></p><p>Once again, I&#8217;m pleased to be offering a course on Ruby and Ruby on Rails at Harvard: <a href="http://extension.harvard.edu/2008-09/courses/csci.jsp#e-168">course</a>; <a href="http://e168f08.plugh.org/">course site</a>.</p>
<p>We&#8217;ll try to avoid this anti-pattern:</p>
<p><a href="http://www.flickr.com/photos/slworking/2218655624/"><img src="http://farm3.static.flickr.com/2238/2218655624_61b2cbbaca.jpg?v=0"/></a></p>
]]></content:encoded>
			<wfw:commentRss>http://7fff.com/2008/08/07/teaching-ruby-and-ruby-on-rails-again-at-harvard/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Capistrano logging</title>
		<link>http://7fff.com/2008/05/15/capistrano-logging/</link>
		<comments>http://7fff.com/2008/05/15/capistrano-logging/#comments</comments>
		<pubDate>Thu, 15 May 2008 11:41:05 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://7fff.com/2008/05/15/capistrano-logging/</guid>
		<description><![CDATA[The logging in Capistrano could be so much better. Just for example, when a task is initiated, that log item should really pop out. At present, the log line starts with &#8220;executing&#8221; for both the indication that a task has been started, and for running a remote command. Because the same word is used, it [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>The logging in Capistrano could be so much better. Just for example, when a task is initiated, that log item should really pop out. At present, the log line starts with &#8220;executing&#8221; for both the indication that a task has been started, and for running a remote command. Because the same word is used, it is hard to see at a glance where you are in a long task. So at present it is:</p>
<pre name="code" class="xml">

   * executing task reload_apache
   * executing &quot;sudo /etc/init.d/apache2 reload&quot;
</pre>
<p>This is lame. Task initiation is important, and should be called out in the first word. Similarly, when a command is run sudo, the fact of &#8220;sudo&#8221; probably has priority over &#8220;executing.&#8221; So for my eyes, at least, something like this would be far more communicative:</p>
<pre name="code" class="xml">

*** Task: reload_apache
  * sudo: &quot;/etc/init.d/apache2 reload&quot;
</pre>
<p>And output and errors might be flagged with two stars.</p>
<p>I bet the changing the logging for the task, at least, would be a quick monkeypatch.</p>
]]></content:encoded>
			<wfw:commentRss>http://7fff.com/2008/05/15/capistrano-logging/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pro Active Record (Book Review)</title>
		<link>http://7fff.com/2007/11/09/pro-active-record-book-review/</link>
		<comments>http://7fff.com/2007/11/09/pro-active-record-book-review/#comments</comments>
		<pubDate>Fri, 09 Nov 2007 15:45:03 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Reviews]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://7fff.com/2007/11/09/pro-active-record-book-review/</guid>
		<description><![CDATA[Kevin Marshall, Chad Pytel, and Jon Yurek, Pro Active Record: Databases with Ruby and Rails (2007). $39.99. [Amazon]
Pro Active Record is all about ActiveRecord, the object-relational mapping layer that comes with Rails. In this review I&#8217;ll call ActiveRecord AR. The book has chapters on SQL, setting up your database, the core features of AR, extra [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>Kevin Marshall, Chad Pytel, and Jon Yurek, <em>Pro Active Record: Databases with Ruby and Rails</em> (2007). $39.99. [<a href="http://www.amazon.com/gp/redirect.html?ie=UTF8&#038;location=http%3A%2F%2Fwww.amazon.com%2FPro-Active-Record-Databases-Rails%2Fdp%2F1590598474%3Fie%3DUTF8%26s%3Dbooks%26qid%3D1194622452%26sr%3D8-1&#038;tag=ce1-20&#038;linkCode=ur2&#038;camp=1789&#038;creative=9325">Amazon</a><img src="http://www.assoc-amazon.com/e/ir?t=ce1-20&amp;l=ur2&amp;o=1" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />]</p>
<p><em>Pro Active Record</em> is all about ActiveRecord, the object-relational mapping layer that comes with Rails. In this review I&#8217;ll call ActiveRecord AR. The book has chapters on SQL, setting up your database, the core features of AR, extra AR goodies, testing and debugging, working with legacy schema, AR and the real world, and, finally, a summary of the AR API (interestingly, the API summary is not a copy of the official docs, but has additional comments from the authors, so there is some real added value in this &#8220;back of the book&#8221; reference material).</p>
<p>Before I begin I want to note that these kinds of framework books and chapters are really hard to write (I know: I contributed to the O&#8217;Reilly JavaEE book). The reason is that a lot of readers come to a subject such as AR without understanding the problem for which AR is the solution. I.e., if you don&#8217;t already have some understanding of relational databases and SQL, and maybe have some experience with different RDBMS from more than one vendor, some of what&#8217;s going on in AR and in this book can be lost.</p>
<p>Generally I would say that if you do any non-vanilla work with AR, you should own this book as a supplement to the account of AR in <em>Agile Web Development with Rails</em>. There is genuinely useful information throughout the text. Here are a few examples that got a check or exclamation point in the margin while I was reading: executing migrations outside of Rails (p. 49); dealing with migrations in source control (p. 53); a nice discussion of writing good tests (pp. 127ff); more detail on the more obscure test assertions than I&#8217;ve seen elsewhere (pp. 129-139); a discussion of transactions and fixtures (p. 141); how to do .csv fixtures (pp. 142-143 &#8212; annoying, by the way; this could be a lot better in AR); good stuff on AR exceptions (pp. 144ff); random notes on legacy schema integration (chapter 7), internationalization (p. 204), use of UUIDs for PKs (p. 205), and some canned associations for typical use cases (pp. 208-209).</p>
<p>The book also handles well the true core of AR, setting up associations between models, and validating models (chapter 4, &#8220;Core Features of ActiveRecord&#8221;). The example &#8220;domain&#8221; is about managing Farmers, Cows, and Milk, which I found just weird and kinky enough that I learned something. A peculiarity of this chapter is that it kicks off with Callbacks rather than Associations and Validations, so a beginning reader is going to have to wait before getting to the core of the core. But I digress.</p>
<p>A brief <em>tour de force</em> is a detailed example of extending AR with Ruby meta-programming (pp. 109-123). This is one of the longer discussions I&#8217;ve seen anywhere regarding AR that provides insight into how it actually works, and how you create your own convenience apparatus for easy-to-write queries.</p>
<p>Now some less good news. The book&#8217;s title makes it sound as though it is going to be complete and exhaustive, but it is not. There are lots of little things that are missing. Just for example, I couldn&#8217;t find a discussion of :source for the has_many :through association, which is necessary in some cases and has vexed my students. In fact, the chapter that gives the API doesn&#8217;t even document ActiveRecord::Associations, which is a major gap (to be sure, there is much information here on associations, but if you&#8217;re going to detail the API for ActiveRecord::Base, why leave out stuff as important as ::Associations?). Another aspect that is missing is dealing with some of the cases where you need to have multiple belongs_to foreign keys: AR can get confused, and it would be helpful if someone played this out at some length; this book doesn&#8217;t do that. Elsewhere, mention is made of a discussion of SQL injection (p. 150), but that discussion never appears.</p>
<p>Had the title been something like &#8220;ActiveRecord Techniques&#8221; I&#8217;d be less concerned about these gaps. I hope they&#8217;ll be addressed in a second edition that is larger and more capacious: We need a single-volume &#8220;big book&#8221; on AR, and this could be it with some additional work.</p>
<p>In sum: Good book! Great bits! 2nd edition has potential to be awesome.</p>
]]></content:encoded>
			<wfw:commentRss>http://7fff.com/2007/11/09/pro-active-record-book-review/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Sigh: Converting from HABTM to has_many :through is easier than I thought . . .</title>
		<link>http://7fff.com/2007/11/04/sigh-converting-from-habtm-to-has_many-through-is-easier-than-i-thought/</link>
		<comments>http://7fff.com/2007/11/04/sigh-converting-from-habtm-to-has_many-through-is-easier-than-i-thought/#comments</comments>
		<pubDate>Sun, 04 Nov 2007 01:07:31 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://7fff.com/2007/11/04/sigh-converting-from-habtm-to-has_many-through-is-easier-than-i-thought/</guid>
		<description><![CDATA[So the Ministry of Truth has had to intervene on my earlier post.
]]></description>
			<content:encoded><![CDATA[<p></p><p>So the Ministry of Truth has had to intervene on my <a href="http://7fff.com/2007/10/31/activerecord-migrating-habtm-to-model-table-suitable-for-has_many-through/">earlier post</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://7fff.com/2007/11/04/sigh-converting-from-habtm-to-has_many-through-is-easier-than-i-thought/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ActiveRecord: Migrating habtm to model table suitable for has_many :through</title>
		<link>http://7fff.com/2007/10/31/activerecord-migrating-habtm-to-model-table-suitable-for-has_many-through/</link>
		<comments>http://7fff.com/2007/10/31/activerecord-migrating-habtm-to-model-table-suitable-for-has_many-through/#comments</comments>
		<pubDate>Wed, 31 Oct 2007 01:35:20 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://7fff.com/2007/10/31/activerecord-migrating-habtm-to-model-table-suitable-for-has_many-through/</guid>
		<description><![CDATA[[Ha, ha, ActiveRecord has the last laugh, and this is much easier than I thought. The Rails Wiki must have been wrong, or it must have been that you couldn't add a primary key in an earlier version of AR.]
ActiveRecord will facilitate many:many relationships across a plain join table that doesn&#8217;t have a primary key. [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>[Ha, ha, ActiveRecord has the last laugh, and this is much easier than I thought. The Rails Wiki must have been wrong, or it must have been that you couldn't add a primary key in an earlier version of AR.]</p>
<p>ActiveRecord will facilitate many:many relationships across a plain join table that doesn&#8217;t have a primary key. This is called &#8220;has and belongs to many.&#8221; It turns out that it is <del datetime="2007-11-04T01:00:30+00:00">hard</del> easy to convert this into a join table where the join table itself represents something.</p>
<p>The example here is a bookmarking application like del.icio.us: you have many users with many links (and <em>vice versa</em>), and model those things as a User class and a Link class. Each User has and belongs to many Links; each Link has and belongs to many Users. As a first cut, you might put the title of the URL in the Link class. So John and Amy might each have a reference to the same link. Note in this model, a catch is that since they share that same Link, it is problematic that the title is on the Link class. Because now they must share that title. Our model prevents one of them from saving his or her link for the NY Times with a personal title such as &#8220;The Yankee-Loving New York Times,&#8221; or some other appropriate moniker. So with that issue in mind, we would like to migrate our schema so that there is a Bookmark class in between User and Link. Now we will put the title in Bookmark, and let the User edit it. If we do this, Amy and John can have bookmarks for the same link (the URL being represented in the Link class) but different titles (in the Bookmark class).</p>
<p>Let&#8217;s take it from the top, shall we? In the original model, if you have a model User, and a model Link, and you want to have a many:many relationship, you can define an association for each one of the form has_and_belongs_to_many :links (and the reverse). Then you create a join table like the following (note the suppression of the primary key):</p>
<pre name="code" class="ruby">

class CreateLinksUsers &lt; ActiveRecord::Migration
  def self.up
    create_table :links_users, :id =&gt; false do |t|
      t.column :link_id,    :integer
      t.column :user_id,    :integer
    end
  end
  def self.down
    drop_table :links_users
  end
end
</pre>
<p>As time proceeds, we discover that we are interested in adding some extra data that should go on the join table. For instance, we might want the time/date when it was added, or notes specific to the relationship between the link and the user&#8230; Or a title, as above. At this point we would need to model it as a first-class (so to speak) ActiveRecord class and use the associations has_many :through for the &#8220;endpoints&#8221; and belongs_to for the in-between class.</p>
<p>Sadly, if you are like me, you might read the Rails Wiki pages before you do anything, and you would read the following which is all wrong:</p>
<p><del datetime="2007-11-04T01:00:30+00:00">Unfortunately, this is tricky because ActiveRecord does not model the original links_users table: It is purely a vehicle for the habtm association. We might think we could rename the table to, say, :bookmarks, and then add a primary key . . . But ActiveRecord does not allow one to add a primary key column to an already-existing table:</del></p>
<blockquote><p>
Note: The API doc on add_column refers to column_types which say that it can be of type :primary_key. This is not true. add_column cannot use :primary_key as a type_ (see <a href="http://wiki.rubyonrails.org/rails/pages/UsingMigrations">Rails Wiki, Using Migrations</a>)
</p></blockquote>
<p>So . . . What to do? One way <del datetime="2007-11-04T01:00:30+00:00">The answer</del> is to create a new bookmarks table, and then model it inside the migration. Loop over your users and links to extract the ids, and add them to the bookmarks. The reverse is much easier: Now you can just drop the primary key and rename the table back to links_users:</p>
<pre name="code" class="ruby">

class CreateBookmarks &lt; ActiveRecord::Migration

  class Bookmark &lt; ActiveRecord::Base; end

  def self.up

    create_table :bookmarks do |t|
      t.column :link_id,     :integer
      t.column :user_id,     :integer
    end

    User.find(:all).each do |u|
      u.links.each do |l|
        Bookmark.create!( :link_id =&gt; l.id, :user_id =&gt; u.id )
      end
    end    

    drop_table :links_users
    print &quot;Change your associations for User and Link to has_many :through =&gt; :bookmarks&quot;

  end

  def self.down
    remove_column :bookmarks, :id
    rename_table :bookmarks, :links_users
    print &quot;Change your associations for User and Link to has_and_belongs_to_many&quot;
  end

end
</pre>
<p>But it can be even easier than that: You might also just add the new primary key going up, and drop it going down:</p>
<pre name="code" class="ruby">

class CreateBookmarks &lt; ActiveRecord::Migration

  class Bookmark &lt; ActiveRecord::Base; end

  def self.up

    rename_table :links_users, :bookmarks
    add_column :bookmarks, :id, :primary_key

    print &quot;Change your associations for User and Link to has_many :through =&gt; :bookmarks&quot;

  end

  def self.down
    remove_column :bookmarks, :id
    rename_table :bookmarks, :links_users
    print &quot;Change your associations for User and Link to has_and_belongs_to_many&quot;
  end

end
</pre>
<p>Yet that&#8217;s not all. <del datetime="2007-11-04T01:00:30+00:00">If you want to preserve data across this migration, you will likely find that information will be lost when you move from the newly-modeled table to the table without the primary key. This is because it is very common to enforce uniqueness on one of the keys in the habtm join table. But when you model a classic many:many join, you probably won&#8217;t do that.<br />
</del> You may find that going &#8220;down&#8221; that you have added data to the has_many :through version that is incompatible with what you had in your habtm model; in which case you are going to have to define a rule to re-organize the data.</p>
]]></content:encoded>
			<wfw:commentRss>http://7fff.com/2007/10/31/activerecord-migrating-habtm-to-model-table-suitable-for-has_many-through/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

