Engines are awesome!! Definitely look at the link Jamie provided in his answer..it is a good starting point. Engines are the way to go with Rails 3. I feel that it is one of the most powerful features of the framework, and I converted almost every piece of common functionality in my apps into engines. IT saves you a ton of time if you are creating alot of apps. Here is my current workflow when creating engines:
Step 1: gem install jeweler
if you dont have it. Then create a blank gem using jeweler.
Step 2: update the Rakefile provided by jeweler with your gem info and any dependencies. You may need to add a filelist so the gemspec can point to the correct files, and exlude any files you dont want when you build it.
gem.files = FileList['lib/**/*.rb','[A-Z]*', 'lib/**/**/*'].to_a
Step 3: Add your Rails application structure - app/controllers, app/views, etc.. to the top-level directory in the gem. You can also include /config directory for your routes.rb which will be appended to your main apps routes.
Step 4: Set up your lib directory like this:
/lib/your_engine_name.rb (require
engine.rb in this file and any other
files in lib that you need)
/lib/your_engine_name/
/lib/your_engine_name/engine.rb
Step 5: Add code to engine.rb:
require 'your_engine_name'
require 'rails'
module YourEngineName
class Engine < Rails::Engine
#load rake tasks go here
#initializers go here
end
end
Step 6: Add all your custom engine code to app/* and lib/your_engine_name/
Step 7: Build the gem using "rake build". You must do this so Bundler can see your files in the gemspec (which is generated when you build) in step #8
Step 8: For local testing reference the local path in the Gemfile of your main application where you want to include the engine:
#Gemfile
gem "your_engine_name", :require => "your_engine_name", :path => "/your_engines/your_engine_name"
Step 9: bundle install and start up your local app server.
Step 10: Since you are referencing the local path, you can make changes to the gem and see them in your main app without rebuilding (unless you need to add new files to the gemspec)
Step 11: put your gem source on github so you can use it in prod. Make use of jewelers versioning rake tasks. I combine some of the rake tasks like this in order to do the git push and tag in the same step and include them in the engine's Rakefile:
namespace :version do
desc "create a new version, create tag and push to github"
task :github_and_tag do
Rake::Task['github:release'].invoke
Rake::Task['git:release'].invoke
end
desc "bump patch push to github"
task :patch_release do
Rake::Task['version:bump:patch'].invoke
Rake::Task['version:github_and_tag'].invoke
end
desc "bump minor push to github"
task :minor_release do
Rake::Task['version:bump:minor'].invoke
Rake::Task['version:github_and_tag'].invoke
end
desc "bump major push to github"
task :major_release do
Rake::Task['version:bump:major'].invoke
Rake::Task['version:github_and_tag'].invoke
end
end
Step 12: When deploying to production, change the source in the Gemfile to github and reference a version tag:
gem 'your_engine_name', :git => '[email protected]:yourusername/your_engine_name.git', :tag=>"v1.1.1"
I am using this hack to reference 2 gem sources in Gemfile until they add that feature to Bundler:
http://www.cowboycoded.com/2010/08/10/using-2-sources-for-a-gem-in-different-environments-with-bundler/
Let me know if you have any problems with this. I am working on a blog post to show this in more detail and I may have left out a few things.. just writing this off the top of my head right now..