Super Rescue
“Super rescue” is not a superhero, it’s a trick for Ruby on Rails developers that, indeed, may rescue you when you’re in trouble.
It involves models’ methods defined like:
class BlogPost < AR::Base
def language
super rescue 'en'
end
end
Yes, that’s actual Ruby.
Generally speaking, it means “attempt to get language in the way of my super class, and if it fails, let’s assume it’s English”.
In practice, Super Rescue is handy when Rails’ rake db:migrate won’t run throughout. The main theme is:
Compatibility with former versions of the database schema
There’s a quite common situation in a Ruby on Rails application that undergoes many iterations : the application code is in sync with the last version of your migrations, not with former ones.
The OMG scenario is the following:
- In a recent migration, you added a brand new model, or a column to another, and you source code reflected this changes by updating a validation, or adding a callback like
after_savethat does some important stuff. - In a former migration, you actually fill in the database with initial data (like an initial admin user, or an initial greeting post, whatever).
- You deploy a brand new copy of your application, and trustfully
rake db:migrateto setup your brand new empty database.
You see the pattern: as migrations run through from the beginning, they’ll eventually trigger parts of your present code that references columns or models that do not exist yet.
An exception abruptly wakes you up: you encounter the incompatibility-with-former-versions-of-the-database-schema syndrome.
Super rescue to the rescue!
You think your migration complains because a column does not exist (yet)?
That’s not quite the case.
Database columns do help Rails building getter and setter methods in your ActiveRecord subclasses. These methods are the indirect way column values are usually accessed.
So, what really do not exist are ruby methods.
So, let’s fool Rails. The language column does not exist yet in the blog_posts table, er, the language method does not exist yet in the BlogPost class? Take that, Rails!
class BlogPost < AR::Base
def language
super rescue 'en'
end
end
Precisely speaking, it means: “let ActiveRecord handle the database access as usual, but should the column not exit, assume a default value”.
And now your
class BlogPost < AR::Base
validates_presence_of :language
end
will succeed, even if the column is still to be created by a future migration.
Super rescue getter/setter
The getter/setter pair can be implemented as:
class BlogPost < AR::Base
def language
super rescue (@language ||= 'en')
end
def language=(value)
super rescue (@language = value)
end
end
And now your
class Blog < AR::Base
has_many :blog_posts
def after_create
blog_posts.create(:content => 'This is your first post', :language => 'en')
end
end
will work like a charm, despite the lack of the language column.
That’s the trick. Simple, effective, and harmless.
It’s not a panacea. It’s unable to handle complex situations. The incompatibility-with-former-versions-of-the-database-schema syndrome lost a battle, not the war.
Thank you for reading.
Posted on novembre 28, 2007 by Gwendal Roué - permalink
Written on décembre 03, 2007, 02h02 by np
Add your comment