Rails 2.2 For Me And For You

The Rails 2.2 release contains a number of big features that are going to be commented on endlessly, especially thread safety, internationalization, and ETag support. Going through the various release notes and what's new documents, I found a lot of smaller features that I'm looking forward to using in future projects, or would have made past projects easier, or are just cool in a framework-geek kind of way.

The concat method no longer needs a block binding

This may be the most subtle change I've ever been this excited about. Let's go back to the bad old days -- last week -- and say that you wanted to write a block helper method like this:

  def label_block(caption, &block)
    content = content_tag("span", caption) + capture(&block)
    concat(content_tag("label", content), block.binding)
  end

It's the block.binding part that was crazy-making. It was an implementation detail that was unfortunately exposed to the programmer (Since the ERb output stream was a private attribute, the method needed direct access to a binding frame to push text into the stream. I think.) Plus, it was off-putting to explain to new Rails programmers, and as an added bonus, made block helpers a total pain to test.

Well, now the ERb output stream is more accessible, and you can now do without the block.binding argument -- in fact, you'll get a DepricationWarning if you use it. You can just remove the argument from the helper, or since you no longer need the explicit block, the helper can now be written in a more Rubyish style:

  def label_block(caption)
    concat("<label>")
    concat("<span>#{caption}</span>")
    yield
    concat("</label>")
  end

I'm also interested to see how this works with my Html generator mini-library

While On The Subject of Blocks

There are two nice additions of things that now take blocks. The first is link_to, as in:

    <% link_to(@project) do %>
      "Caption"
      <%= image_tag(@project.image_url) %>
    <% end %>

Also, partials now take blocks, meaning they can act somewhat like layouts.

The partial itself can contain a yield:

   <table>
     <tr><td>
       <%= yield %>
     </td></tr>
   </table>

Then the call to the partial can include a block:

<% render :partial => "table_partial" do %>
  <%= @project.name %>
<% end %>

And the yield command invokes the block, as you would expect

Rails Guides

For this release, Rails has added a number of in-depth guides to various and sundry rails features, accessible at http://guides.rubyonrails.org/ or by rake doc:guides from your command line.

Better error message for assert_difference

Speaking of minor changes that make me happy, the error message for an assert_difference failure now actually contains the text of the failing expression, as in "<projects.count> was the expression that failed". I actually saw this one in my testing before I saw it in the release notes. Since it's pretty common for me to nest assert_difference calls when multiple objects are being created at one time, this made me smile.

Performance Tests

And.... another chapter of my book gets further out of date with the inclusion of performance tests that are essentially wrappers around the ruby-prof profiling module. A new generator, performance_test, places tests in a test/performance directory. Inside each test you can do integration test style calls to controllers, and you get nice ruby-prof profiling reports on the results.

This feature, at least in, release candidate, does not seem totally polished. Couple of notes -- it requires ruby-prof 0.6.1, which is not the version available via regular gem methods, it seems like you need to get it at github, and install via the directions here.

There also isn't a rake task to run the performance tests, you need to run them as individual Ruby scripts, which means, if you are like me, then you will be scrambling a bit to make sure the Rails environment loads properly.

second through tenth

This is the sort of nearly pointless syntactic sugar that I love. I mean, nearly pointless in the best and most respectful way, because I plan to use this all over the place. It's actually very Lisp-like...

>> players = %w(who what i_dont_know today tomorrow why because i_dont_care)
=> ["who", "what", "i_dont_know", "today", "tomorrow", "why", "because", "i_dont_care"]
>> players.second
=> "what"
>> players.fifth
=> "tomorrow"

I would love to see a knock-down drag-out argument about the merits of players.second versus players[1]...

assert_sql

This may seem a little esoteric, but I have a reporting feature where I would have used this test extensively. Probably good for searches too. It checks for a match between the argument to the method and SQL generated inside the block.

should "produce correct sql" do
  assert_sql(/LIKE 'me'/) do
    Product.report(params)
  end
end

StringInquirer

I like this because it's such a nice Rails metaprogramming thing.

>> role = ActiveSupport::StringInquirer.new("admin")
=> "admin"
>> role.admin?
=> true
>> role.user?
=> false

I like it. Here's the entire implementation of the class

  class StringInquirer < String
    def method_missing(method_name, *arguments)
      if method_name.to_s[-1,1] == "?"
        self == method_name.to_s[0..-2]
      else
        super
      end
    end
  end

That's pretty.

Rails scaffolds now generate belong_to links

And finally...

script/generate scaffold task name:string project:references

Will now generate

class Task < ActiveRecord::Base
  belongs_to :project
end

A small thing, but useful.