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.
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”
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.
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:
- Complying, either with a direct interface on your object or a shim that provides the interface.
- Proxy, which maps your object’s interface to the expected one.
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.
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.
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.
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.