The maze book for programmers!
mazesforprogrammers.com

Algorithms, circle mazes, hex grids, masking, weaving, braiding, 3D and 4D grids, spheres, and more!

DRM-Free Ebook

The Buckblog

assorted ramblings by Jamis Buck

Plugging into Rails

11 October 2005 — A convention for Rails plugins in introduced — 2-minute read

So, you’ve got a new acts_as_chunky_bacon mixin you want to add to ActiveRecord, but those villianous core team members have turned you down and called you unworthy. What other options do you have? People need this mixin. You understand that in Ruby, things ought to act like chunky bacon.

It used to be (in that dim age before the 2005 RubyConf) that your only recourse was to package the thing up and tell people to go through the hassle of putting your mixin somewhere, adding it to their load-path, and requiring the file.

No more! Edge Rails now sports a very-simple-but-effective plugin system. You, as the author, can now give someone a zip file and tell them to simply uncompress it into their vendor/plugins directory—and that’s it. No more configuration required by the user.

All you, as the author, need to do is create a project with the following directory structure:

  acts_as_chunky_bacon/
  acts_as_chunky_bacon/init.rb
  acts_as_chunky_bacon/lib
  acts_as_chunky_bacon/lib/acts_as_chunky_bacon.rb

When the application starts, the lib directory will be automatically added to the load path, and the init.rb automatically loaded. (Either may be absent.) The init.rb just needs to do something like the following:

  ActiveRecord::Base.send :include, ActsAsChunkyBacon

What does this mean? It means that consumers of your plugin only need to drop your project in their vendor/plugins directory, and then start applying it to their own model objects:

  class PoignantGuide < ActiveRecord::Base
    acts_as_chunky_bacon :from => "chapter 3" 
    ...
  end

Currently, we at 37signals are using this plugin system to share code between our various applications. We are using it for things like email notification on errors, or common before_filter’s, or our web service infrastructure that allows Backpack and Basecamp to integrate with Writeboard.

I really like this new plugin system. It probably isn’t perfect, yet—I’m sure people will find ways to make it even handier—but it really makes it a lot easier to share code. Hopefully it will also make it easier for the Rails core team to say “no” to many proposed new features, since many of them can now be more easily shared as third-party additions.

Reader Comments

Basecamp + Writeboard? Wow, that's the last big gaping hole that will make Basecamp much more useful. Hopefully this is the new feature being pushed at 10 pm tonight... In the meantime, it would be great if there was some kind of gem hook-in so Rails plugins could be easily updated with the gems system. Maybe doing a require or include in init.rb that refers to an installed gem? Or is that too awkward?
Very nice!
topfunky: i had the same thought about gems. Though, I'm not sure that's up to the plugins to decide. One idea I had was distributing a gem that sets up a generator. Type script/generate plugin acts_as_chunky_bacon, and it writes the default files to vendor/plugin/ (init.rb, default templates, etc). On the other hand, storing all the files in vendor/plugin is handy for those with restrictive web hosts...
Rick, I've been leaning towards the plugin-installer generator, too. Perhaps it would just install an init.rb stub in vendor/plugins/whatever that loaded the gem-installed plugin. Having plugins in vendor/plugins is handy, though, because it allows your application to be distributable without requiring a bunch of dependencies. For 37signals, we use svn:externals to depend on our in-house plugins, which is quite convenient.
It IS Writeboards! Thank you, Jamis. I will name my first child after you.
Really good, keep going! Good job!
Hey Jamis - hopefully you'll get a chance to read the email I've just sent - I think the Rails team I work in might have developed a superset of this functionality which you guys might be interested in absorbing into Rails... Essentially, we can drop in vertical appliation slices (or 'frameworks' as we call them), complete with models, views, controllers - all overridable by the users own code - and manage them as svn:externals for swift and efficient bugfixing. Let me know what you think!
Jamis, you're a stud! Fantastic.
jamis, very nice.
A tiny tweak: how about letting plugins just be installed as zips, and let Rails do the rest? One less step, one more customer?
What about supporting plugins as RubyGems? I want to be able to do: gem install chunk-bacon-1.1 echo chunk-bacon-1.1 >> environment/plugins Or something like that.
Hmm... Formatting didn't work. Lets try again: gem install chunk-bacon-1.1 echo chunk-bacon-1.1 >> environment/plugins
Oh yeah! Good work guys
Robert Brook--zipped plugins would be nifty. A patch would be lovely. :) Jon Tirsen: ditto :) Seriously, there is plenty of room for improvement in the current implementation. And as ever, the fastest way to see your wishes fulfilled, is to fulfill them yourself and submit a patch.
Nice work. You mentioned subscriptions work at 37Signals. I'm looking for the ability to have people subscribe to a Typo blog so that they can receive email when the site is updated, preferably batched at the end of the day. Know of any code that can be used as a base to get that functionality added to Typo?
Brian, not off-hand. However, RSS-feeds are what are typically used these days for that kind of notification. People can easily subscribe to the RSS feeds and be notified with each new article. If you really want email notification, you could manage that as a separate daemon that runs nightly. It just reads the RSS feed, determines if anything new has been added since the last run, and if so, fires off an email to the subscribers.
Any plan for a repository yet?
ctran, only thinking. We've been so focused on getting 1.0 ready that we haven't been doing any work at all on peripherals. That said, if some third party wanted to start organizing a central location for people to distribute their plugins from, that'd be cool.
Why not just use RubyForge to host the plugins?