A point of some confusion to a developer learning Ruby on Rails is the difference between using gems and plugins. They both offer out-of-the-box, third party functionality, and yet they have remarkable differences. Thanks to GitHub it’s very easy to write, host and share your own gems and plugins, so here is a quick review of their differences.
Rails Plugins
The Ruby on Rails framework comes with a specific architecture for loading plugins that can change and augment your application and the Rails framework itself. When your Rails app is loaded, this is the order in which code is loaded:
- The Rails framework is loaded (either from vendor/rails or the Rails gems).
- All plugins are loaded from vendor/plugins.
- Your application code in app and lib is loaded.
Because of this order, plugins can use code in the Rails framework, it can override the framework, and then it can be used within your application code.
Plugins must live in vendors/plugins, so the installed code will be localized in your code repository. The good news is that should you need to alter the plugin in any way, you can go in and hack away at the code without affecting your other apps. Unfortunately, your favorite plugin will have to be installed each time you create a new app (unless you’re using the new Rails Templates).
Rails plugins have the flexibility to hook into every part of Rails, including generators, rake tasks and tests/specs. They are specific to Rails, however, and could not be (directly) used with another Ruby framework (Merb, Sinatra, etc.). Personally, I think that any functionality that solely extends the Rails framework should always be a plugin rather than a gem, simply because that gem couldn’t be used outside of Rails anyways.
Ruby Gems
Gems are a facility of the Ruby language and have no dedicated connection to the Rails framework. Ruby gems are highly portable chunks of Ruby code that can be used inside any Ruby script or application. Thanks to its distributed architecture, one quick ‘gem install’ command can search RubyForge, GitHub and other repositories at the same time so that you don’t need to know where that gem lives to install it.
Gems are saved on your machine once and then included into applications using ‘require’. Naming conventions can be tricky, however, when gems are stored on GitHub or when the author did not stick to regular conventions. For example, this will install my iTermWindow gem from GitHub:
sudo gem install chrisjpowers-iterm_window
To use the gem in code, however, it looks like this:
require 'rubygems' require 'iterm_window'
Regardless, RubyGems make it very easy to make functionality available in all your Ruby apps and scripts. It is important, though, to make sure that you have all the correct gems installed on all your development machines and staging/production servers, and that they all are using the same versions of the gems.
To avoid the problem of missing dependencies, Rails gives you a rake task to copy the gem files locally in your project in vendor/gems. Your gems will be saved in your repository and distributed along with your app when you use this task:
rake gem:unpack
Please note that this will not work for all gems — some gems have more complex C bindings and native extensions that cannot be unpacked into vendor.
Different Tools for Different Jobs
While Ruby gems and Rails plugins have similar effects in your application, they obviously vary significantly in their architecture. Ultimately, each will prove more or less useful in a given scenario. As I mentioned before, my rule of thumb is to make Rails-specific functionality a plugin while making more general Ruby libraries into gems.
So now that you know the differences, get onto GitHub and start sharing some code!
Posted by chrisjpowers