From Rails to Rack: Making Rails 3 a Better Ruby Citizen (Yehuda Katz)

May 31, 2009 Pivotal Labs

Yehuda’s GoRuCo talk was on the subject of Rails as a Ruby citizen – that while Rails was already a pretty good Ruby Citizen with 2.3, 3.0 is about making it a better citizen.

Who is the Rails Developer?

Many are building apps on top of Rails, not considering making an extension, just building on what’s available. Others are building extensions full-time. In the vast many are power users working on long-term projects, building apps primarily, but in the course of it making tweaks and extensions to Rails.

What Does it mean to be a Ruby Citizen?

Rails is built on many other Ruby libraries: Rack, Test::Unit, Erb (soon to be replaced with Erubis).

Other libraries use Rails as a library, e.g Spree, ActiveMerchant, Radiant, Sproutcore.

Also, Rails works with other libraries, and can be optionally used with them, for example as in the case of Haml.

Rack as an example of the benefits of Citizenry

Prior to Rack, frameworks would right special handlers for each of its interfaces, with all sorts of attendant inconsistencies. Rack, when introduced, seemed to solve this problem, and so was incorporated into Merb.

But Rack is actually much more than this. It enables you to write Middleware, which is components of code integrated to the generic Rack interface. This enables functionality to be consolidated into single-purpose middleware components, with all other components remaining ignorant of the others.

In Rails 2.3, they applied Rack to Rails, making each controller a middleware endpoint selected by the router, which was another middleware component.

But good Rack endpoints don’t do dispatching, they just pass-through one-to-one. So in 3.0, the router will point at a specific action.

Middleware

As with ruby libraries in general, Rails is a citizen in the Rack ecosystem, using Rack, working with other Middleware, and providing its own which is then used in other frameworks.

To this end, Rails 3.0 will split out things like rescuing, params parsing and session handling into middleware which is then usable downstream without pulling in all of Rails.

In Rails you can use middleware via “config.middleware.use Foo”

Integration Tests

By generalizing Rails via Rack, Rails is able to use generalized Integration testing by simply treating Integration test as a Server which issues commands to the Rails stack via the standard Rack interface. Already Rails 3.0 works with rack-test.

ORM Agnosticism

Why does ORM agnosticism matter? ActiveRecord is Ruby, DataMapper is Ruby, one should be able to just require the alternative and use the library.

But Rails has dependencies on the ORM, for example in the form_for helper, which works for a specific interface.

Merb 1.0 offered “Agnosticism” by offering 2 interfaces, one for ActiveRecord, one for DataMapper. If you wanted to work with merb, you had to offer one of those interfaces, as CouchDB did.

To provide a general solution, Rails needs to provide a standard abstract interface which anyone can implement in order to interface with Rails.

One can meet this interface by:

  1. Complying, either with a direct interface on your object or a shim that provides the interface.
  2. Proxy, which maps your object’s interface to the expected one.

Javascript

Rails remote_form_for looks pretty in the template, but generates a bunch of Prototype-specific javascript code. But Rails would like to provide better support for jRails, which implements the Rails javascript helpers in a jQuery equivalent.

The solution is to emit markup rather than javascript, which the respective javascript libraries then bind to, via event delegation.

Rails will ship with the prototype version of this, Yehuda is planning to write the jQuery equivalent, Mootools and others will provide their equivalents as well.

You’re also able to bind to this markup in Javascript as well, providing your own alternative to jQuery, Mootools, &c. bindings.

Filters

In Rails 2.3, simple actions would spend 20% of their time in filters. Filters are important in small applications which do a lot of traffic and performance-intensive apps.

Historically, parts of Rails filters (Before, After, Conditions) had been factored out into ActiveSupport, but Around filters and skipping were more difficult to filter out, and so hadn’t been. Rails 3.0 integrates all the rails filtering in a performant way.

In 2.3, Rails asks the filter a bunch of questions, even if it’s a simple filter, which you’d expect to be fast, then sends. This checking is runtime, when all the necessary information is available in advance.

Rails 3.0 uses metaprogramming to compile the various filters down into a single method which is simple and quick.

Abstract Controller

Action Mailer and Action Controller had diverged and require separate implementations on many fronts. The better way is to call use modules to attach functionality to either class, from a common base. It uses super to iterate over each modules implementation in order.

The result is a bunch of layers doing a single thing, taking and producing normalized data. You can remix and insert your own equivalents.

In Rails 3.0 one can set _action_view method with a renderer object which then implements alternatives to or extensions on the Rails action_view helpers.

FastController

Equivalent to ActionController, with expensive modules excluded, to which you can attach your own functionality.

On of Yehuda’s goals: “How easy would it be to implement Sinatra on top of Rails?”

Likewise, how can Rails be made such that it’s functionality is more available to other projects such as CloudKit.

Q & A

In Q & A, Yehuda notes that in Rails you can get away without knowing too much about inheritance and subclassing, while “more crazy” languages force you to know this. He hopes that Rails 3.0 will bring more awareness of this to Ruby.

About the Author

Biography

Previous
Hypertable and Rails: DB Scaling Solutions with HyperRecord
Hypertable and Rails: DB Scaling Solutions with HyperRecord

Every site based on a RDBMS will eventually hit a database scalability bottleneck. In this session we will ...

Next
Magic Scaling Sprinkles
Magic Scaling Sprinkles

Nick Kallen uses live coding demos to show how to scale your massive web application with distribution, bal...