Upgrading Ruby for Rails3 – Installment 3

If you’re following along, I’ve been trying to get an old up from Rails 2.3 up to Rails 3.x (previous installments 1, 2).

After a bunch of refactoring and clean up, I was able to get my coverage report to an acceptable level. The app was running successfully on Rails3.0. Now to try to upgrade ruby.

  • Update my Gemfile & .ruby-version files to use ruby 1.9.3
  • Dump rcov from the Gemfile (eventually I’ll replace that with simplecov
  • bundle and run tests
  • clean up the mess
  • undefined method `each' for String

    No problem. I dug in to find a test trying to parse an http response body by newlines. Apparently ruby-1.8.7 String would handle this.

    The fix was simple

    
    -    resp.body.each do |row|
    +    resp.body.split("\n").each do |row|
    

    Scopes with arguments

    I’m not proud to admit it but I had a scope defined which both took an argument (not such a bad thing) but then wrote custom SQL based on that parameter. A combo of changes related to how lambda arguments are handled by scopes and the way the arguments were passed into the scope caused troubles. The fix was something like this (note: the model names have been changed to protect the innocent):

    
    -  scope :participants, lambda { |*key|
    -    q = key.blank? ? Conf.participant_key : key
    -    joins(:extra_info).where("extra_infos.participation like '%%{q}%%'")
    +  scope :participants, lambda { |key|
    +    q = (key.blank? ? Conf.participant : key).to_s
    +    joins(:extra_info).where("extra_infos.participation like '%#{q}%'")
    

    If you forget about the fact that I was pushing a string unprotected into a SQL query, the two things that seemed to cause issues were the splat on the lambda’s input args and the double ‘%’ in the query string. This change at least made the code behave as it used to.

    This code is actually doing a bunch of work that could be handled with serialize :participation, Array. I’ve added a chore for myself to make that change before I go further. More about serialize can be found here.

    Even after fixing that, the scope worked fine with arguments, but was very unhappy in cases where I had nil args which lead to more failing tests. In the end, I refactored the scope into a method and it made the whole thing much simpler.

    
    def self.participants(key = nil) 
      q = key || Conf.participant
      joins(:extra_info).where("extra_infos.participation like '%#{q}%'")
    end
    
    

    Symbols to Strings

    The final straw was updating a few tests that counted on public_instance_methods. The test tried to grab all controller methods and run simple checks that methods existed. public_instance_methods returned strings in Ruby 1.8.7 and symbols in the new.

    
    1.8.7>  CatalogController.public_instance_methods(false)
    => ["index"]
    
    
    1.9.3>  CatalogController.public_instance_methods(false)
    => [:index]
    

    A quick fix (map the result to strings) got everything back in line.

    Well that was easy, how about ruby2.0.0?

    Once I had that rolling, what’s the harm in running all the way to ruby2.0.0?

    Following the same steps, I updated the Gemfile and .ruby-version. Rebundled, and started fixing issues.

    String#start_with?

    It turns out that ruby2.0.0, String#start_with?does not allow a nil input. This causes stylesheet_link_tag to fail because in Rails 3.0.20, it does the following:


    # actionpack-3.0.20/lib/action_view/helpers/asset_tag_helper.rb:749
    if has_request && include_host && !source.start_with?(controller.config.relative_url_root)

    and it seems that Rails 3.0.20 does not set relative_url_root by default. (more discussion here on stackoverflow)

    After adding a quick patch to my application.rb

    ActionController::Base.config.relative_url_root = ''

    everything was back in line.

    insert_record not available on Array

    This was the last big error that came up during tests. It seems that to get around this, I needed to move to Rails 3.1. Feeling like I was on a roll, I happily started more migrating.

    • Updated Rails to 3.1.12
    • Updated mysql2 gem and removed the activerecord-mysql2-adapter
    • added simplecov
    • removed tmail gem
    • remove config.action_view.debug_rjs from Rails config files
    • moved restful_authentication files into lib (from vendor/plugins)
    • upgraded restful_authentication to use AASM directly (instead of acts_as_state_machine method
    • Update references to Fixtures to use ActiveRecord::Fixtures

    And with that, I was on Ruby-2.0 and Rails-3.1. Not too shabby.

    I’m still not using the asset pipeline, but feel like I’m in a good place to make that jump to Rails3.2 and only have to worry about getting the pipeline in place.

    Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s