It can be hard to write plugins for Ruby on Rails. Here is a “simple” example to extend ActiveRecord (slightly modified), from the official Ruby on Rails site:
module Yaffle def self.included(base) base.send :extend, ClassMethods end module ClassMethods def acts_as_something send :include, InstanceMethods end end module InstanceMethods def to_yaffle "You are a Yaffle!" end end end ActiveRecord::Base.send :include, Yaffle
This code is downright baffling, if, like me, you’re not intimately comfortably with the world of Ruby metaprogramming. It’s easy enough to copy and paste your methods under ClassMethods and InstanceMethods, as the tutorial suggests, and hope things work, but it’s hard to understand what’s going on here. And I like to understand these things.
For example, are the module names ClassMethods and InstanceMethods special to Ruby, or are they arbitrary? It’s hard to tell.
And what the heck does this code mean?
def self.included(base) base.send :extend, ClassMethods end
What is “base” referring to here? What is “extend” (as opposed to “include”)? This code was a complete mystery to me.
The first step was to figure out that last question – what “extend” meant. I found this very useful writeup by John Nunemaker explaining the difference. Essentially, when you “include” a module in a class, the objects created by that class have all the methods of that module (instance methods). When you use “extend” instead, the methods apply to the class (class methods).
And we can see the last line is forcing ActiveRecord::Base to “include” the module:
ActiveRecord::Base.send :include, Yaffle
So far so good.
At this point, any methods in Yaffle should be added to the class ActiveRecord::Base. But there’s a caveat: when you package your methods in submodules, however, none of those methods are included or extended or whatever. They are ignored (to the best of my knowledge).
It turns out that there is a hook you can use when you include a module in a class – you can define an “included” method in the module that is called when a class actually includes the module. It is roughly akin to a constructor for the module.
So after all that, this is how the plugin above works: The first thing that happens is that you include the module in ActiveRecord::Base. That action does one thing – it triggers the “included” method of the module. That then calls extend on ActiveRecord::Base, this time directly targeting the submodule “ClassMethods” which does contain methods. So at this point all your class methods are loaded up into ActiveRecord::Base.
What about the instance methods? In most cases, you want to control which subclasses of ActiveRecord::Base include the instance methods. So you let the user explicitly call a special class method (in this case, “acts_as_something”) that has the class call “include” on the InstanceMethods submodule, which in turn provides the instance methods for objects made from that class.
Anyway, this seems to me to be overly complicated. Calling “include” in order to indirectly call “extend” doesn’t make much sense to me. This code works perfectly well:
module Yaffle #class methods def acts_as_yaffle send :include, InstanceMethods end module InstanceMethods def to_yaffle "You are a Yaffle!" end end end ActiveRecord::Base.send :extend, Yaffle
Much more concise, in my opinion. If you don’t like the lack of symmetry between the class methods and the instance methods (*cough* OCD), you can always package the class methods in a submodule as before, and change the last line to
ActiveRecord::Base.send :extend, Yaffle::ClassMethods. Same thing, and just as easy to understand.
Whew, that’s all for now! Long post – I hope it helps someone :-)
p.s. I know that gems are replacing plugins, but the issues are exactly the same.
Jon Crosby has an excellent talk from Mountain West Ruby Conference 2009 about how middleware is taking over web development. His article “A World of Middleware” is a bit difficult to parse if you don’t know Rack, so I’ll try to simplify what he’s saying a bit…
Rails 2.3 is built on Rack, which is a simple specification to connect web frameworks like Rails and Merb with web servers like Mongrel and Thin. Rails 2.3 also lets you define middleware code to be run before Rails is invoked, again using Rack. In Rails terms, middlewares are like before_filter’s that are run before Rails is ever even called. Another way of looking at a middleware is like a miniature application that can connect, via Rack, to another middleware. Each middleware stack handles certain requests (for example, certain url’s can be handled by specific middlewares), or all requests. If the middleware returns 404, the next middleware is called. Rails 2.3 only handles requests that fall to the bottom of the middleware stack.
Crosby’s point is, why bother with a chain of middlewares leading up to an application? All you need is a chain of middlewares that are the application. His example in the talk is an authentication middleware that sits on top of everything else, instead of the authentication layer being part of a monolithic application.
The best part is that middlewares can be created as black boxes, and simply included in your Rack application (or used as a middleware in your Rails 2.3 application). And it looks like the best tool for creating simple middlewares is Sinatra. This stuff isn’t even on the main Sinatra site yet, but you can read about it on the Sinatra blog. To quote: “multiple Sinatra applications can now be run in isolation and co-exist peacefully with other Rack based frameworks.” This is awesome – it means that a Sinatra application can be used as middleware for a Rails application (or other Sinatra applications). So it’s easy to build a big application by chaining together smaller Sinatra middlewares.
Since Ruby’s open source community is so strong, there’s no doubt we will be seeing pluggable middlewares that fit easily inside any Rack application. This is exciting stuff, and I look forward to building an app this way!
Web development typically follows a specific set of steps. There are different workflows for different people, and I’m not trying to establish a best-practices workflow here (just the opposite, as you’ll see), but the differences are usually in the order in which the steps are performed, not the actual steps themselves.
The first step (again, conceptually the first, not necessarily chronologically) is to design a database for the application’s needs – the database tier. That means breaking down the various components of your blog into tables. For example, if you are building a blog engine, you would need at least a table for articles and another for comments.
The second step is to write a “middleware” tier – that just means software that sits in between the client and the the database. You don’t want people to connect to the database directly or they’d be able to wreak havoc. The middleware tends to be where you do things like keeping track of who’s allowed on what page.
The last step would be to design a “view” or “presentation” tier to let your clients interact with your database in a (hopefully) safe manner. The view tier, among other things, takes the data that is broken up into tables and puts it back together again.
Ruby on Rails, which I’ve loved for years, excels at connecting these dots. ActiveRecord, which I consider the crown jewel of Rails, does a fantastic job at simplifying the complex job of creating and managing the database, for example. Rails also handles the middleware tier quite well with ActionController. The view tier (ActionView) doesn’t add all that much, but server-side view tiers rarely do when it comes to the web.
This is all going to be obsolete with CouchDB*.
What makes CouchDB so damn disruptive is not the fact that it beats frameworks like Rails – it’s that it completely side-steps them. CouchDB dispenses with structured tables altogether, relying on “documents” instead. Documents are arbitrarily complex data structures that contain as much or as little data as you need. The (partially completed) free book on the official site uses the example of the business card. Some business cards have fax numbers, and some don’t. Some have website addresses, and some don’t. In a classic, structured database, you would need to have a column in the database for fax numbers, even if only one business card in your database has one, because the structure of the database has to be in place before the data is added. If the structure doesn’t accommodate the data, then the structure has to be altered, which is always a potentially dangerous thing (Rails handles this with migrations). CouchDB lets you put whatever data you want in whatever document (in this case, business card) you want. That means that instead of having to add a fax number column to every business card in the database, you could simply add a fax number to the new document and only the new document.
ActiveRecord is amazing at simplifying all the structured SQL stuff. But once that complexity starts to go away, the value added by ActiveRecord starts dropping off dramatically. If the database tier is already super-simple, why bother with a fairly hefty helper library on top of that? CouchDB itself makes ActiveRecord (and other fancy ORM’s, like Hibernate) largely obsolete (and even quaint).
Another cool feature of CouchDB is that it uses HTTP for all interactions. That means that the database runs on a web server. Since CouchDB has built-in HTTP features like authentication, cookies, and caching, there’s not much the middleware tier is needed for, especially given that CouchDB works directly with AJAX, so much more logic can be put in the browser.
The last thing is the view tier – getting the data back to the user**. CouchDB uses something called MapReduce, invented at Google, to deal with searching through existing data. It’s a little tricky, and possibly the only thing preventing me from jumping fully on board with CouchDB. Instead of SQL queries, you write “view functions” for CouchDB. The end result is pretty much the same.
As an aside, one of the coolest thing about view functions is that they can be stored in CouchDB directly. You just give them a unique identifier (like “view-blog-articles-by-date”) and store them as documents in CouchDB. That means application code can be stored in the database, which is great because backing up the database will backup a good chunk of your code as well.
So in conclusion, a lot of what makes Rails great, and it is great, is deprecated by this humble open source application. I didn’t even get to the built-in scalability that CouchDB has going for it. CouchDB is a Big Deal, and I’m keeping my eye on it.
* To qualify slightly, the concepts introduced by CouchDB are going to be disruptive, whatever form they take (i.e. even if CouchDB itself doesn’t take off).
** I’m fudging the presentation tier and the view tier a bit, in case you’re nitpicky ;-) This post is not MVC-compliant.
I haven’t seen this documented anywhere, but it looks like Ruby on Rails picked up something nice from the Merb playbook: The
Rails class now has the properties
env. That means that instead of typing
RAILS_ROOT, you can type
Rails.root (just like
Merb.root). Why bother, you ask? Because it’s much cleaner to keep all the Rails configuration stuff in one namespace. It also looks nicer in code. Mainly, it’s something I liked about Merb that I thought was missing in Rails, so I’m happy to see this kind of positive give-and-take between the two communities.
RAILS_ENV are probably not going anywhere anytime soon, but I think this a step in the right direction.