Class: Rails::Engine

Inherits:
Railtie show all
Defined in:
lib/rails/engine.rb,
lib/rails/engine/configurable.rb,
lib/rails/engine/configuration.rb

Overview

Rails::Engine allows you to wrap a specific Rails application and share it accross different applications. Since Rails 3.0, every Rails::Application is nothing more than an Engine, allowing you to share it very easily.

Any Rails::Engine is also a Rails::Railtie, so the same methods (like rake_tasks and generators) and configuration available in the latter can also be used in the former.

Creating an Engine

In Rails versions before to 3.0, your gems automatically behaved as Engine, however this coupled Rails to Rubygems. Since Rails 3.0, if you want a gem to automatically behave as Engine, you have to specify an Engine for it somewhere inside your plugin lib folder (similar with how we spceify a Railtie):

# lib/my_engine.rb
module MyEngine
  class Engine < Rails::Engine
  end
end

Then ensure that this file is loaded at the top of your config/application.rb (or in your Gemfile) and it will automatically load models, controllers and helpers inside app, load routes at “config/routes.rb”, load locales at “config/locales/*”, load tasks at “lib/tasks/*”.

Configuration

Besides the Railtie configuration which is shared across the application, in a Rails::Engine you can access autoload_paths, eager_load_paths and autoload_once_paths, which differently from a Railtie, are scoped to the current Engine.

Example:

class MyEngine < Rails::Engine
  # Add a load path for this specific Engine
  config.autoload_paths << File.expand_path("../lib/some/path", __FILE__)

  initializer "my_engine.add_middleware" do |app|
    app.middleware.use MyEngine::Middleware
  end
end

Paths

Since Rails 3.0, both your Application and Engines do not have hardcoded paths. This means that you are not required to place your controllers at “app/controllers”, but in any place which you find convenient.

For example, let's suppose you want to lay your controllers at lib/controllers, all you need to do is:

class MyEngine < Rails::Engine
  paths.app.controllers = "lib/controllers"
end

You can also have your controllers being loaded from both “app/controllers” and “lib/controllers”:

class MyEngine < Rails::Engine
  paths.app.controllers << "lib/controllers"
end

The available paths in an Engine are:

class MyEngine < Rails::Engine
  paths.app                 = "app"
  paths.app.controllers     = "app/controllers"
  paths.app.helpers         = "app/helpers"
  paths.app.models          = "app/models"
  paths.app.views           = "app/views"
  paths.lib                 = "lib"
  paths.lib.tasks           = "lib/tasks"
  paths.config              = "config"
  paths.config.initializers = "config/initializers"
  paths.config.locales      = "config/locales"
  paths.config.routes       = "config/routes.rb"
end

Your Application class adds a couple more paths to this set. And as in your Application, all folders under “app” are automatically added to the load path. So if you have “app/observers”, it's added by default.

Direct Known Subclasses

Application, Plugin

Defined Under Namespace

Modules: Configurable Classes: Configuration

Constant Summary

Constants inherited from Railtie

Railtie::ABSTRACT_RAILTIES

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Railtie

abstract_railtie?, console, generators, #load_console, #load_generators, log_subscriber, railtie_name, rake_tasks, subclasses

Methods included from Initializable

included, #initializers, #run_initializers

Class Attribute Details

.called_fromObject

Returns the value of attribute called_from


94
95
96
# File 'lib/rails/engine.rb', line 94

def called_from
  @called_from
end

Class Method Details

.find_root_with_flag(flag, default = nil) ⇒ Object


111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/rails/engine.rb', line 111

def find_root_with_flag(flag, default=nil)
  root_path = self.called_from

  while root_path && File.directory?(root_path) && !File.exist?("#{root_path}/#{flag}")
    parent = File.dirname(root_path)
    root_path = parent != root_path && parent
  end

  root = File.exist?("#{root_path}/#{flag}") ? root_path : default
  raise "Could not find root path for #{self}" unless root

  RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ?
    Pathname.new(root).expand_path : Pathname.new(root).realpath
end

.inherited(base) ⇒ Object


99
100
101
102
103
104
105
106
107
108
109
# File 'lib/rails/engine.rb', line 99

def inherited(base)
  unless base.abstract_railtie?
    base.called_from = begin
      # Remove the line number from backtraces making sure we don't leave anything behind
      call_stack = caller.map { |p| p.split(':')[0..-2].join(':') }
      File.dirname(call_stack.detect { |p| p !~ %r[railties[\w\-\.]*/lib/rails|rack[\w\-\.]*/lib/rack] })
    end
  end

  super
end

Instance Method Details

#eager_load!Object


134
135
136
137
138
139
140
141
# File 'lib/rails/engine.rb', line 134

def eager_load!
  config.eager_load_paths.each do |load_path|
    matcher = /\A#{Regexp.escape(load_path)}\/(.*)\.rb\Z/
    Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
      require_dependency file.sub(matcher, '\1')
    end
  end
end

#load_tasksObject


129
130
131
132
# File 'lib/rails/engine.rb', line 129

def load_tasks
  super
  config.paths.lib.tasks.to_a.sort.each { |ext| load(ext) }
end