Rails 3 Internals: Railtie & Creating Plugins

With the official Rails 3 release on the horizon, all of the edge features we have been hearing about for over a year are about to become the new standard, and it has definitely been worth the wait. One of the primary goals of the "big refactor" has been to modularize Rails to allow other frameworks to easily extend or entirely replace any of the previously "critical" components (ActiveRecord, ActionMailer, etc). At the centre of all this, is the new Railtie logic, which pieces all of these modules together.

Getting started with Railtie

The documentation for Railtie is a great place to get started, but the interesting observation is that each of the major Rails components (Action Mailer/Controller/View/Record) is itself a Railtie, and Rails as you know it is simply pieced together by requiring all of the independent components. Even better, if your plugin or gem needs to hook into the Rails initialization process, all you need to do is inherit from Railtie and you are ready to go!

So how does Railtie know to call your classes and initializers? Railtie defines a self.inherited method, which is called anytime a subclass of Railtie is created, and stashes a reference to this class in a @subclasses variable. From there, the framework can simply call Railtie.subclasses and perform all the initialization as usual - a clever use of the Ruby object model.

Creating a Rails 3 plugin: 0-60

As a result of the refactor, creating Rails 3 plugins is at least several orders of magnitude simpler. In fact, as a simple exercise, lets create a custom notification plugin to print all of the internal Rails logging by also hooking into the new Rails::Notification API:

module NewPlugin
  # namespace our plugin and inherit from Rails::Railtie
  # to get our plugin into the initialization process
  class Railtie < Rails::Railtie

    # configure our plugin on boot. other extension points such
    # as configuration, rake tasks, etc, are also available
    initializer "newplugin.initialize" do |app|

      # subscribe to all rails notifications: controllers, AR, etc.
      ActiveSupport::Notifications.subscribe do |*args|
        event = ActiveSupport::Notifications::Event.new(*args)
        puts "Got notification: #{event.inspect}"
      end

    end
  end
end

Believe it or not, that is a fully functional Rails 3 plugin, in 10 lines of code. Simply drop this file into your load path and require it in your application. In fact, you can bundle this file into a gem, ship it to Gemcutter and with the help of Bundler, all your users have to do is specify gem 'ournew-plugin' in their Gemfile, and the rest is taken care of. With a little more imagination, and fun, we can extend our example above into a 'slowgrowl' plugin, which will - you guessed it - growl at the developer anytime it detects a slow code path in your app! Hat tip to Gavin Stark for the idea.

Getting started with Rails 3

Railtie while an important piece of Rails 3, is hardly the only component worth looking into. Also read up on the changes in ActiveRecord, the new router, watch the summary screencasts on the Rails site, and make sure to check out one of the many great Railscasts on the topic by Ryan Bates. It has been worth the wait, Rails 3 is easily head and shoulders above the competition.


Ilya Grigorik

Ilya Grigorik is a web performance engineer and developer advocate at Google, where his focus is on making the web fast and driving adoption of performance best practices at Google and beyond.