Coupa and Rails 2

Vote on HN

Joy and churchbells this morning here in sunny San Mateo! David smacked down Rails 1.2.3 with a heavy hand and replaced it with the newer and shinier Rails 2.1.1. Here's what's rocking and not-so-rocking with the upgrade.

For starters, the upgrade was completely painless from my perspective. It was really as easy as:

sudo gem install rails  # to update rails to 2.1.1
svn up

That's it! script/server started up fine, and all was happy... Until I logged in. Then I was confronted with the not-so-friendly exception:

ActionController::RenderError (You called render with invalid options : {:layout=>false, :action=>"cloud_portlet"}, nil):
/Library/Ruby/Gems/1.8/gems/actionpack-2.1.1/lib/action_controller/base.rb:847:in `render_with_no_layout'
/Library/Ruby/Gems/1.8/gems/actionpack-2.1.1/lib/action_controller/layout.rb:260:in `render_without_benchmark'
/Library/Ruby/Gems/1.8/gems/actionpack-2.1.1/lib/action_controller/benchmarking.rb:51:in `footnotes_original_render'
/Library/Ruby/Gems/1.8/gems/activesupport-2.1.1/lib/active_support/core_ext/benchmark.rb:8:in `realtime'
/Library/Ruby/Gems/1.8/gems/actionpack-2.1.1/lib/action_controller/benchmarking.rb:51:in `footnotes_original_render'
/vendor/plugins/footnotes/lib/textmate_initialize.rb:12:in `render'

It turns out the old Textmate footnotes plugin doesn't play well with new Rails. A simple svn rm and we were on our way.

Unfortunately, Textmate wasn't the only broken plugin.

ScopedAccess and named_scope

ScopedAccess was also broken. ScopedAccess allowed us to impose conditions on ActiveRecord finders in our controllers. For example, to show only budget adjustments made on a specific budget, I had the following ScopedAccess filter defined on the budgets controller.

around_filter, { |controller|
    { :find => { :conditions => ['budget_line_id = ?', controller.params[:id]] } }
  :only => [:show, :show_owned ]

This filter wraps around the :show and :show_owned action. Whenever find is called on BudgetLineAdjustment, the :conditions hash it passed in with the finder. This worked pretty well and I didn't think it breached MVC design.

Arguably, it's the model's job to limit and filter what's accessible. That's exactly what Rails 2.x does. We've refactored our ScopedAccesses with named_scope at the model layer. The above example now lives in BudgetLineAdjustment:

class BudgetLineAdjustment
  named_scope :for_budget_line,
              lambda { |budget_line|
                { :conditions => ['budget_line_id = ?',] }
  # ... snip


Initially, we didn't plan on switching to Rails 2 this sprint. The original plan was to scrap LoginEngine and UserEngine from the project to prepare to migrate to Rails 2. Replacing Engines just a tedious scan through all the Engine code we used and selectively copying over the code that we wanted to keep. Initially I thought that I would have a hell of a time migrating this to fit with restful_authentication, but it wasn't bad and I removed tons of code.


Cosmetically, we renamed all the views to be suffixed with .html.erb rather than .rhtml.

Riding on Rails (2)

Migrating to Rails 2 was a straight forward project. It didn't require any new design. We just had to make sure that whatever was working before continued to work after the migration. I'm super thankful that we decided to tackle this project early in our sprint because it gave up plenty of time to catch small silly things. There were plenty benefits to migrating to Rails 2. We could remove a lot of the backports of Rails 2 features that we had previously kept in lib/rails_extensions.rb. The whole system felt a bit snappier, especially in development. The development logs were actually useful again because they weren't fill with deprecation warnings and noise from the Engines code. This is what it must feel like to be the cool kid on the block.

comments powered by Disqus