Friday, 26 October 2007

How to upgrade Ruby on Rails Restful routes to 2.0

Ok, you were quite proud when on Rails 1.2.x you made your app restful.
Now in 2.0 REST has been improved cleaned reworked and... changed the naming of the nested Routes

Let's take a look at the differences in 1.2.x

the following code


map.resources :dinners do |dinner|
dinner.resources :dishes do |dish|
dish.resources :side_courses
end
dinner.resources :drinks
end


would generate (among many others)


dinners_url
dinner_url

dishes_url
dish_url

side_courses_url
side_course_url

drinks_url
drink_url


and so on.
With the same code in the routes rails 2.0 generates


dinners_url
dinner_url

dinner_dishes_url
dinner_dish_url

dinner_dish_side_courses_url
dinner_dish_side_course_url

dinner_drinks_url
dinner_drink_url


And your REST routes methods will change more if you use the new routes namespacing introduced with 2.0
This is good and much nicer, and is a great help in complicated applications that use the same resources at different nesting levels and for different purposes.

But it means that to migrate from 1.2.x you've got to change many of your original calls to the *_url or *_path methods.

Well, I wrote a small dodgy script to manage the search and replace of the old routes with the new ones.

And I thought I'd share it...

The script should run as it is on linux. It uses find/grep/sed system commands.

first two steps are quite simple


  1. upgrade a non critical copy of your rails app to version 2.0 of ruby on rails

  2. download the script to migrate your routes from 1.2 to 2.0 and save it in the root directory of your rails project

  3. execute script/console and type the following

    require 'route_migrator'

    RouteMigrator.dump_current_route_methods


  4. exit from the console and open with a text editor the file route_map_2_0.rb. This file should contain a ruby hash with keys and values containing the old routes

  5. now you have to update the values of the hash with the new routes, for the previous example a line would look like


    "side_courses_url" => "side_courses_url"


    and you need to update it to


    "side_courses_url" => "dinner_dish_side_courses_url"


    If you don't have a clear idea about what the new routes are you can use

    rake routes


    or open again script/console and type


    require 'route_migrator'

    RouteMigrator.dump_named_routes

    Be aware of that the hash might contain some rubbish as keys, just delete the lines that you think aren't proper routes actually used in your applications,

  6. When you think your hash is complete and ready to go you can check your work firing yet another time your script/console and typing

    require 'route_migrator'

    RouteMigrator.check_new_routes

    This will output a warning if you've typed in the hash some routes that are not in the list generated from 2.0

  7. If the previous check succeeded you can try the following that will substitute every occurrence odf your old routes with the new ones
    WARNING: this script is guaranteed to screw up >>BADLY<< your code if you use it without understanding what it does. Read the source code of the script before proceeding. As always svn diff and svn revert will be your friends

    require 'route_migrator'

    RouteMigrator.upgrade_route_methods!

    At this point your application should be updated with the new routes

6 comments:

macournoyer said...

Hey Paolo, nice article,
you're missing and end in the first code block

hungryblank said...

Thanks macournoyer I think it should be fixed now.

GlennFord said...

I gave this a shot but when I ran the code at step 3 it wrote a file on my machine named route_coll.txt and it grew really fast. After it reached about 1.6gb I killed the process and removed the file. Thoughts?

hungryblank said...

@glennford

I'm pretty sure the script is trying to parse the log of your app or you have some symbolic links in place that create a sort of loop in your application code.

I've modified the script to make it analyze only the "app" dir.

Let me know if is any better.

GlennFord said...

That did the trick! Instead of doing step 5 I altered the code to call "check_new_routes" on the keys created with "dump_current_route_methods". This was a quicky on line 22 with:
"#{m}" => ""
becoming
"#{m}" => "#{m}"
In doing so, rather than searching all 50+ of my routes for their correct counterparts manually, it simply told me I had 3 non-existing routes. Very helpful! I'm tracking them down now and fixing them. Thanks so much for your helpful code!

hungryblank said...

@glennford

thanks a lot, I've included your change in the script!!