How to upgrade plugins to Rails 3.0
Rails 3.0 beta is out and it's now time to upgrade all the plugins available. To show you how to do it I've decided to create a small plugin compatible with Rails 2.x and Rails 3.0. It's a wrapper around Rack::Cache to insert it automatically in a Rails application.
It's a gem
First things first we create the gem we will name rails-cache. Thanks to Jeweler it's dead easy. Just a few lines of code in a Rakefile and it's done:
require "rake"
begin
require "jeweler"
Jeweler::Tasks.new do |gem|
gem.name = "rails-cache"
gem.summary = "Add Rack::Cache to your Rails app"
gem.email = "nicolas.merouze@gmail.com"
gem.homepage = "http://github.com/nmerouze/rails-cache"
gem.authors = ["Nicolas Mérouze"]
gem.files = Dir["*", "{lib}/**/*"]
gem.add_dependency("rack-cache", "~> 0.5.2")
end
Jeweler::GemcutterTasks.new
rescue LoadError
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
end
To create the VERSION file a echo "1.0.0" > VERSION is enough.
Rails 2.x way
The code of the gem will be in lib/rails/cache.rb and it's just the insertion of the Rack::Cache middleware:
require "rack/cache"
Rails.configuration.middleware.use Rack::Cache,
:metastore => "file:#{Rails.root + "cache/rack/meta"}",
:entitystore => "file:#{Rails.root + "cache/rack/body"}",
:verbose => true
We build the gem with rake build and we install it with gem install --local pkg/rails-cache-1.0.0.gem. Then we need to load it in our environment.rb:
RAILS_GEM_VERSION = '2.3.5' unless defined? RAILS_GEM_VERSION
require File.join(File.dirname(__FILE__), 'boot')
Rails::Initializer.run do |config|
config.gem "rails-cache", :lib => "rails/cache"
end
Rack::Cache is now plugged with the Rails application!
The new way
Rails 3.0 comes with Bundler. A cool thing with Bundler is that you can load a gem which have a custom path:
gem "rails-cache", :require => "rails/cache", :path => "../rails-cache"
The :path option is the path to our gem. We have a lot of solution to do the same in Rails 2.x, with a plugin instead of a gem for example, but it is not as elegant as with Bundler (Bundler is usable with Rails 2.x).
To create a plugin for Rails there's an object for that now, Rails::Railtie. So we just need to write an object which inherit from Rails::Railtie in lib/rails/cache.rb:
require "rack/cache"
module Cache
class Railtie < Rails::Railtie
railtie_name :rails_cache
initializer "rails_cache.insert_rack_cache" do |app|
app.config.middleware.use Rack::Cache,
:metastore => "file:#{Rails.root + "cache/rack/meta"}",
:entitystore => "file:#{Rails.root + "cache/rack/body"}",
:verbose => true
end
end
end
The gem has been upgraded to Rails 3.0!
Rails 2.x and 3.0 in a gem
This is just an example here, but it's possible there's a better solution:
require "rack/cache"
if Rails::VERSION::MAJOR == 2
Rails.configuration.middleware.use Rack::Cache,
:metastore => "file:#{Rails.root + "cache/rack/meta"}",
:entitystore => "file:#{Rails.root + "cache/rack/body"}",
:verbose => true
else
module Cache
class Railtie < Rails::Railtie
railtie_name :rails_cache
initializer "rails_cache.insert_rack_cache" do |app|
app.config.middleware.use Rack::Cache,
:metastore => "file:#{Rails.root + "cache/rack/meta"}",
:entitystore => "file:#{Rails.root + "cache/rack/body"}",
:verbose => true
end
end
end
end
And you can find the whole code on GitHub.
More about Plugins/Engines
- José Valim has written a draft documentation about Rails::Railtie, Rails::Engine and Rails::Application.
- Yehuda Katz has made a blog post about it.
- rails3_datamapper is a good example to see how to write a Rails 3.0 plugin.
- The latest commits for CarrierWave have been made to upgrade it to Rails 3.0.