Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rails Engines. Doing It Wrong. And Then Right.

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers. →

Rails Engines. Doing It Wrong. And Then Right.

Avatar for Robert Glaser

Robert Glaser

October 13, 2011

More Decks by Robert Glaser

Other Decks in Programming

Transcript

  1. What‘s a Railtie? • Core of the framework • Provides

    hooks to extend Rails • ActiveRecord, ActionController etc. are all Railties
  2. Our problem • Build a vocabulary and thesauraus management system

    • Adjust and extend it for every customer without forking it
  3. The problem • Could not act as a standalone app

    • Always had to be plugged into a main app
  4. The problem • A Rails 3.0 Engine can not act

    as a standalone app by default (requires customization) • No out-of-the-box support for migrations, assets etc.
  5. …only if we want to # config/initializers/iqvoc.rb unless Iqvoc.const_defined?(:Application) require

    File.join(File.dirname(__FILE__), '../../lib/engine') end # config/application.rb module Iqvoc class Application < Rails::Application
  6. Up next: Engine tasks # lib/engine.rb class Engine < Rails::Engine

    paths.lib.tasks << "lib/engine_tasks" Only available when app is mounted as an engine!
  7. What about Migrations? namespace :iqvoc do namespace :db do task

    :migrate => :environment do ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true path = Iqvoc::Engine.find_root_with_flag("db").join('db/migrate') ActiveRecord::Migrator.migrate(path, ENV["VERSION"] ? ENV["VERSION"].to_i : nil) Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby end end end
  8. Rails 3.1 # Main app Rails.application.routes.draw do mount Foo::Engine =>

    "/foo" end # Engine Foo::Engine.routes.draw do …
  9. Rails 3.1 Namespace isolation module MyEngine class Foo < Rails::Engine

    isolate_namespace Foo end end # Separate routers for each Engine foo.root_path main_app.root_path
  10. Assets task :link do Iqvoc.for_static_folders do |source_common_dir, target_common_dir| File.unlink(target_common_dir) if

    File.symlink?(target_common_dir) && ENV['force'] == "true" if !File.exists?(target_common_dir) puts "Linking #{source_common_dir} -> #{target_common_dir}" File.symlink(source_common_dir, target_common_dir) else puts "Symlink #{target_common_dir} already exists!" end end end
  11. Forget about that: group :development do gem 'iqvoc', :path =>

    '../iqvoc' end group :production do gem 'iqvoc', :git => '[email protected]:innoq/iqvoc.git' end