The Blurring Line Between Plugins and Gems
Now that there is something called gem dependencies in Rails, which refers to the ability to specify what gems a Rails application requires from within that application itself, the line between plugins and gems has gotten a little blurry. For those that are new to Rails or unaware of the new features, let's go through a little bit about what these things are.
Rails Plugins
Rails plugins are pieces of code that can be added to a Rails application on at the application level, and reside in the vendor/plugins folder of that application. Plugins are simple to install by simply typing:
script/plugin install plugin_name
from within the root directory or a Rails application. The main feature to plugins is that they install in each application, and are specific to that application.
Ruby Gems
Ruby gems are also pieces of ruby code that can be added to a system running Ruby, just as simply as adding plugins to an application:
gem install gem_name
However, gems are installed at a system level, which means that rather than being specific to a Rails application, like a plugin is, gems are available to all Rails applications that are running on the same system. In other words, you would install a gem on your web server, where it is available to all Rails applications running on that web server. In contrast, a plugin is installed within a Rails application and it's methods are available only to that application.
So What Is A GemPlugin?
One of the issues that is being addressed by gem dependencies is that of making sure that a system has the required gems in order or properly run a Rails application. By adding a line such as:
config.gem "chronic"
inside the initializer block of an application's config/environment.rb file you can state that this application requires the latest version of the chronic gem. You can also specify a source for the gem, and also the version that of the gem that this application requires.
Not only can we now specify that an application needs a particular gem, but also which version of that gem. This tackles an issue that pops up a lot, which is gem versions. Actually, it pops up a lot with plugins as well, since different applications can have various versions of a particular plugin.
So now that we can declare gem dependencies, we can easily keep track of versions, so it make sense to create GemPlugins, which are plugins that can be installed like gems.
Creating A GemPlugin
Let's assume that you already have a plugin that you have created, hosted at Github and it is working great. To install the plugin for a Rails application, you usually use:
script/plugin install git://github.com/your_name/plugin_name.git
In order to gemify this plugin, follow these simple steps:
- Create a
rails/init.rbfile in your repository, and copy the contents of your currentinit.rbfile to that one. - Change your
init.rbfile to contain onlyrequire File.dirname(__FILE__) + "/rails/init". - Create a
plugin_name.gemspecdocument in the root directory or your repository. Check the gemspec reference for more information. - Go to the plugins "edit" page at Github, and check the
RubyGembox.
Each time you push a new gemspec document up to your repository, Github will rebuild the gem. Your plugin can now be installed as a gem, or it can be installed as a traditional plugin.
One of the reasons for doing this is so that you can require specific versions of a plugin in a Rails application. By including the following line in our environment.rb file:
config.gem "plugin_name", :source => git://github.com/your_name/plugin_name.git, :version => "~>0.2.3"
We can tell a Rails application that it needs at least version 0.2.3 of the gem called plugin_name, which can be found at the Github repository given.
Not only that, but we can also use plugins across many Rails applications now without having to install them into each one. Pagination is a great example of this, where the will_paginate used to be the defacto way of doing things when they removed pagination in Rails 2.0. However, just about every application that I have created uses pagination in some form or another, and installing the plugin for each application was becoming redundant. To solve this the prefered method is to use the gem version of the plugin and requiring it in each application:
config.gem 'mislav-will_paginate', :version => '~> 2.3.4', :lib => 'will_paginate', :source => 'http://gems.github.com'
In the end, the move to gems is a good one. I personally like the option of installing a plugin as both a gem and a plugin. Since some plugins you will only use on one application, it's nice to be able to keep those in with the application. However, for plugins that I use with multiple applications I like the ability to make a GemPlugin, so that I can install the "plugin" only once and have it's methods be available to all applications on that system.
With any luck, this helps someone out there to manage their plugins a little more efficiently.
This post is filed under Developers' Corner and has the following keyword tags: ruby, rails, plugin, gem, gemplugin.
2 Comments
Armando Roggio says:
Very Nice.
pjb3 says:
One caveat is that as of now, GemPlugins can't define rake tasks, whereas plugins can.