Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 255 lines (222 sloc) 8.48 kb
b17e358 @josevalim Move configuration to subfolders.
josevalim authored
1 require 'rails/railtie'
812136a @jeremy Fix unstated usage of Pathname
jeremy authored
2 require 'active_support/core_ext/module/delegation'
3 require 'pathname'
53c13f1 @anildigital Use Config::CONFIG['host_os'] instead of RUBY_PLATFORM [#4477 state:reso...
anildigital authored
4 require 'rbconfig'
c787bfd @drogus Engine can now load its own plugins
drogus authored
5 require 'rails/engine/railties'
7fcf859 @josevalim Massive cleanup in Railties and load stack.
josevalim authored
6
7 module Rails
781d0a9 @josevalim Add docs for Railtie, Engine, Plugin and Application.
josevalim authored
8 # Rails::Engine allows you to wrap a specific Rails application and share it accross
de0753d @mikel Editing the railties/../railtie.rb and engine.rb docs
mikel authored
9 # different applications. Since Rails 3.0, every Rails::Application is nothing
10 # more than an Engine, allowing you to share it very easily.
781d0a9 @josevalim Add docs for Railtie, Engine, Plugin and Application.
josevalim authored
11 #
12 # Any Rails::Engine is also a Rails::Railtie, so the same methods (like rake_tasks and
13 # generators) and configuration available in the latter can also be used in the former.
14 #
15 # == Creating an Engine
16 #
17 # In Rails versions before to 3.0, your gems automatically behaved as Engine, however
18 # this coupled Rails to Rubygems. Since Rails 3.0, if you want a gem to automatically
19 # behave as Engine, you have to specify an Engine for it somewhere inside your plugin
20 # lib folder (similar with how we spceify a Railtie):
21 #
22 # # lib/my_engine.rb
23 # module MyEngine
24 # class Engine < Rails::Engine
25 # end
26 # end
27 #
28 # Then ensure that this file is loaded at the top of your config/application.rb (or in
45e6028 @wycats Removing Metal from Rails 3.
wycats authored
29 # your Gemfile) and it will automatically load models, controllers and helpers
781d0a9 @josevalim Add docs for Railtie, Engine, Plugin and Application.
josevalim authored
30 # inside app, load routes at "config/routes.rb", load locales at "config/locales/*",
31 # load tasks at "lib/tasks/*".
32 #
33 # == Configuration
34 #
35 # Besides the Railtie configuration which is shared across the application, in a
6f83a50 @fxn renames load_(once_)paths to autoload_(once_)paths in dependencies and c...
fxn authored
36 # Rails::Engine you can access autoload_paths, eager_load_paths and autoload_once_paths,
781d0a9 @josevalim Add docs for Railtie, Engine, Plugin and Application.
josevalim authored
37 # which differently from a Railtie, are scoped to the current Engine.
38 #
39 # Example:
40 #
41 # class MyEngine < Rails::Engine
42 # # Add a load path for this specific Engine
6f83a50 @fxn renames load_(once_)paths to autoload_(once_)paths in dependencies and c...
fxn authored
43 # config.autoload_paths << File.expand_path("../lib/some/path", __FILE__)
4bacc2a @josevalim Update the documentation for Engine and Railtie.
josevalim authored
44 #
45 # initializer "my_engine.add_middleware" do |app|
20f0e9f @jeremy Fix docs typo: app.middlewares -> app.middleware
jeremy authored
46 # app.middleware.use MyEngine::Middleware
4bacc2a @josevalim Update the documentation for Engine and Railtie.
josevalim authored
47 # end
781d0a9 @josevalim Add docs for Railtie, Engine, Plugin and Application.
josevalim authored
48 # end
9cfeefb @wycats Reorganized initializers a bit to enable better hooks for common cases w...
wycats authored
49 #
781d0a9 @josevalim Add docs for Railtie, Engine, Plugin and Application.
josevalim authored
50 # == Paths
51 #
de0753d @mikel Editing the railties/../railtie.rb and engine.rb docs
mikel authored
52 # Since Rails 3.0, both your Application and Engines do not have hardcoded paths.
781d0a9 @josevalim Add docs for Railtie, Engine, Plugin and Application.
josevalim authored
53 # This means that you are not required to place your controllers at "app/controllers",
54 # but in any place which you find convenient.
55 #
56 # For example, let's suppose you want to lay your controllers at lib/controllers, all
57 # you need to do is:
58 #
59 # class MyEngine < Rails::Engine
60 # paths.app.controllers = "lib/controllers"
61 # end
62 #
63 # You can also have your controllers being loaded from both "app/controllers" and
64 # "lib/controllers":
65 #
66 # class MyEngine < Rails::Engine
67 # paths.app.controllers << "lib/controllers"
68 # end
69 #
70 # The available paths in an Engine are:
71 #
72 # class MyEngine < Rails::Engine
73 # paths.app = "app"
74 # paths.app.controllers = "app/controllers"
75 # paths.app.helpers = "app/helpers"
76 # paths.app.models = "app/models"
77 # paths.app.views = "app/views"
78 # paths.lib = "lib"
79 # paths.lib.tasks = "lib/tasks"
80 # paths.config = "config"
81 # paths.config.initializers = "config/initializers"
82 # paths.config.locales = "config/locales"
83 # paths.config.routes = "config/routes.rb"
84 # end
85 #
86 # Your Application class adds a couple more paths to this set. And as in your Application,
87 # all folders under "app" are automatically added to the load path. So if you have
88 # "app/observers", it's added by default.
89 #
7fcf859 @josevalim Massive cleanup in Railties and load stack.
josevalim authored
90 class Engine < Railtie
b17e358 @josevalim Move configuration to subfolders.
josevalim authored
91 autoload :Configurable, "rails/engine/configurable"
92 autoload :Configuration, "rails/engine/configuration"
788fce2 @josevalim Create configurable modules and ensure that they are added only on direc...
josevalim authored
93
7fcf859 @josevalim Massive cleanup in Railties and load stack.
josevalim authored
94 class << self
95 attr_accessor :called_from
96
395d664 @josevalim Move application configuration to the application configuration object, ...
josevalim authored
97 # TODO Remove this. It's deprecated.
98 alias :engine_name :railtie_name
e548f96 @josevalim Rename plugin_name to railtie_name and engine_name.
josevalim authored
99
7fcf859 @josevalim Massive cleanup in Railties and load stack.
josevalim authored
100 def inherited(base)
f5ee855 @josevalim Improve heuristic for railties default name, otherwise railties may be n...
josevalim authored
101 unless base.abstract_railtie?
788fce2 @josevalim Create configurable modules and ensure that they are added only on direc...
josevalim authored
102 base.called_from = begin
a5684df @josevalim Ensure config.after_initializer is executed before building the middlewa...
josevalim authored
103 # Remove the line number from backtraces making sure we don't leave anything behind
1477a61 @aaronchi Fix called_from under Windows so engines works properly
aaronchi authored
104 call_stack = caller.map { |p| p.split(':')[0..-2].join(':') }
b1b922d @jeremy Revert "Revert "Application detection should also allow dots in the path...
jeremy authored
105 File.dirname(call_stack.detect { |p| p !~ %r[railties[\w\-\.]*/lib/rails|rack[\w\-\.]*/lib/rack] })
788fce2 @josevalim Create configurable modules and ensure that they are added only on direc...
josevalim authored
106 end
7fcf859 @josevalim Massive cleanup in Railties and load stack.
josevalim authored
107 end
788fce2 @josevalim Create configurable modules and ensure that they are added only on direc...
josevalim authored
108
7fcf859 @josevalim Massive cleanup in Railties and load stack.
josevalim authored
109 super
110 end
111
788fce2 @josevalim Create configurable modules and ensure that they are added only on direc...
josevalim authored
112 def find_root_with_flag(flag, default=nil)
7fcf859 @josevalim Massive cleanup in Railties and load stack.
josevalim authored
113 root_path = self.called_from
114
115 while root_path && File.directory?(root_path) && !File.exist?("#{root_path}/#{flag}")
116 parent = File.dirname(root_path)
117 root_path = parent != root_path && parent
118 end
119
02c5137 @josevalim Add view paths to Engine setup.
josevalim authored
120 root = File.exist?("#{root_path}/#{flag}") ? root_path : default
7fcf859 @josevalim Massive cleanup in Railties and load stack.
josevalim authored
121 raise "Could not find root path for #{self}" unless root
122
bb75c33 @spastorino Config is deprecated on 1.8.8 and 1.9.3 use RbConfig
spastorino authored
123 RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ?
13d66cd @josevalim Extract Railtie load from application.
josevalim authored
124 Pathname.new(root).expand_path : Pathname.new(root).realpath
7fcf859 @josevalim Massive cleanup in Railties and load stack.
josevalim authored
125 end
b5975a4 @drogus Delegate non existing class methods to instance for Engine
drogus authored
126
127 protected
128
129 def method_missing(*args, &block)
130 instance.send(*args, &block)
131 end
7fcf859 @josevalim Massive cleanup in Railties and load stack.
josevalim authored
132 end
133
9cfeefb @wycats Reorganized initializers a bit to enable better hooks for common cases w...
wycats authored
134 delegate :paths, :root, :to => :config
2b75b94 @josevalim Plugin is now an Engine.
josevalim authored
135
136 def load_tasks
7317d9e @josh Remove implicit controller namespacing from new dsl
josh authored
137 super
2b75b94 @josevalim Plugin is now an Engine.
josevalim authored
138 config.paths.lib.tasks.to_a.sort.each { |ext| load(ext) }
139 end
140
351816f @josevalim Ensure that eager_load actually takes place just after the middleware st...
josevalim authored
141 def eager_load!
142 config.eager_load_paths.each do |load_path|
143 matcher = /\A#{Regexp.escape(load_path)}\/(.*)\.rb\Z/
144 Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
145 require_dependency file.sub(matcher, '\1')
146 end
147 end
148 end
149
c787bfd @drogus Engine can now load its own plugins
drogus authored
150 def railties
151 @railties ||= Railties.new(config)
152 end
153
ad6be08 @drogus Made Engine valid rack app with its own middleware stack
drogus authored
154 def app
155 @app ||= config.middleware.build(endpoint)
156 end
157
158 def endpoint
c989d1a @drogus Engine sets routes as default rack endpoint if no endpoint was given
drogus authored
159 self.class.endpoint || routes
ad6be08 @drogus Made Engine valid rack app with its own middleware stack
drogus authored
160 end
161
162 def call(env)
163 app.call(env)
164 end
165
c989d1a @drogus Engine sets routes as default rack endpoint if no endpoint was given
drogus authored
166 def routes
167 @routes ||= ActionDispatch::Routing::RouteSet.new
168 end
169
675f3ea @drogus Gather initializers from railties in engines to get rid of additional lo...
drogus authored
170 def initializers
171 initializers = []
172 railties.all { |r| initializers += r.initializers }
173 initializers += super
174 initializers
175 end
176
7fcf859 @josevalim Massive cleanup in Railties and load stack.
josevalim authored
177 # Add configured load paths to ruby load paths and remove duplicates.
9cfeefb @wycats Reorganized initializers a bit to enable better hooks for common cases w...
wycats authored
178 initializer :set_load_path, :before => :bootstrap_hook do
9b19a6f @josevalim A few changes were done in this commit:
josevalim authored
179 _all_load_paths.reverse_each do |path|
4ae7936 @josevalim Got tests working once again.
josevalim authored
180 $LOAD_PATH.unshift(path) if File.directory?(path)
181 end
7fcf859 @josevalim Massive cleanup in Railties and load stack.
josevalim authored
182 $LOAD_PATH.uniq!
183 end
184
185 # Set the paths from which Rails will automatically load source files,
186 # and the load_once paths.
9cfeefb @wycats Reorganized initializers a bit to enable better hooks for common cases w...
wycats authored
187 #
188 # This needs to be an initializer, since it needs to run once
189 # per engine and get the engine as a block parameter
190 initializer :set_autoload_paths, :before => :bootstrap_hook do |app|
9b19a6f @josevalim A few changes were done in this commit:
josevalim authored
191 ActiveSupport::Dependencies.autoload_paths.unshift(*_all_autoload_paths)
192 ActiveSupport::Dependencies.autoload_once_paths.unshift(*config.autoload_once_paths)
7fcf859 @josevalim Massive cleanup in Railties and load stack.
josevalim authored
193
98240c4 @josevalim Get rid of initializers global and create i18n railtie.
josevalim authored
194 # Freeze so future modifications will fail rather than do nothing mysteriously
6f83a50 @fxn renames load_(once_)paths to autoload_(once_)paths in dependencies and c...
fxn authored
195 config.autoload_paths.freeze
9b19a6f @josevalim A few changes were done in this commit:
josevalim authored
196 config.eager_load_paths.freeze
6f83a50 @fxn renames load_(once_)paths to autoload_(once_)paths in dependencies and c...
fxn authored
197 config.autoload_once_paths.freeze
7fcf859 @josevalim Massive cleanup in Railties and load stack.
josevalim authored
198 end
199
226d8e7 @josevalim Refactor MetalLoader and RoutesReloader to rely less on class configurat...
josevalim authored
200 initializer :add_routing_paths do |app|
84ebfa4 @josevalim Ensure metals and initializers in plugins are loaded.
josevalim authored
201 paths.config.routes.to_a.each do |route|
226d8e7 @josevalim Refactor MetalLoader and RoutesReloader to rely less on class configurat...
josevalim authored
202 app.routes_reloader.paths.unshift(route) if File.exists?(route)
98240c4 @josevalim Get rid of initializers global and create i18n railtie.
josevalim authored
203 end
204 end
205
7317d9e @josh Remove implicit controller namespacing from new dsl
josh authored
206 # DEPRECATED: Remove in 3.1
e0bdc4f @josevalim Ensure namespaced controllers in engines work.
josevalim authored
207 initializer :add_routing_namespaces do |app|
84ebfa4 @josevalim Ensure metals and initializers in plugins are loaded.
josevalim authored
208 paths.app.controllers.to_a.each do |load_path|
e0bdc4f @josevalim Ensure namespaced controllers in engines work.
josevalim authored
209 load_path = File.expand_path(load_path)
028e54c @josevalim Add mailers to paths in case someone wants to access it directly and ens...
josevalim authored
210 Dir["#{load_path}/*/**/*_controller.rb"].collect do |path|
d03196c @phs Regexp.escape(load_path) in add_routing_namespaces initializer [#4442 st...
phs authored
211 namespace = File.dirname(path).sub(/#{Regexp.escape(load_path)}\/?/, '')
e0bdc4f @josevalim Ensure namespaced controllers in engines work.
josevalim authored
212 app.routes.controller_namespaces << namespace unless namespace.empty?
213 end
214 end
215 end
216
1177a40 @josevalim Fix i18n locales order test.
josevalim authored
217 # I18n load paths are a special case since the ones added
218 # later have higher priority.
98240c4 @josevalim Get rid of initializers global and create i18n railtie.
josevalim authored
219 initializer :add_locales do
fed72b5 @josevalim Rename engines_load_path to railties_load_path.
josevalim authored
220 config.i18n.railties_load_path.concat(paths.config.locales.to_a)
7fcf859 @josevalim Massive cleanup in Railties and load stack.
josevalim authored
221 end
222
02c5137 @josevalim Add view paths to Engine setup.
josevalim authored
223 initializer :add_view_paths do
84ebfa4 @josevalim Ensure metals and initializers in plugins are loaded.
josevalim authored
224 views = paths.app.views.to_a
4aded43 @wycats Replace the placeholder base_hook API with on_load. To specify some code...
wycats authored
225 ActiveSupport.on_load(:action_controller) do
226 prepend_view_path(views)
227 end
228 ActiveSupport.on_load(:action_mailer) do
229 prepend_view_path(views)
230 end
02c5137 @josevalim Add view paths to Engine setup.
josevalim authored
231 end
232
6690d66 @josevalim Rename config.cookie_secret to config.secret_token and pass it as config...
josevalim authored
233 initializer :load_config_initializers do
84ebfa4 @josevalim Ensure metals and initializers in plugins are loaded.
josevalim authored
234 paths.config.initializers.to_a.sort.each do |initializer|
98240c4 @josevalim Get rid of initializers global and create i18n railtie.
josevalim authored
235 load(initializer)
02c5137 @josevalim Add view paths to Engine setup.
josevalim authored
236 end
7fcf859 @josevalim Massive cleanup in Railties and load stack.
josevalim authored
237 end
238
351816f @josevalim Ensure that eager_load actually takes place just after the middleware st...
josevalim authored
239 initializer :engines_blank_point do
240 # We need this initializer so all extra initializers added in engines are
241 # consistently executed after all the initializers above across all engines.
7fcf859 @josevalim Massive cleanup in Railties and load stack.
josevalim authored
242 end
788fce2 @josevalim Create configurable modules and ensure that they are added only on direc...
josevalim authored
243
244 protected
245
9b19a6f @josevalim A few changes were done in this commit:
josevalim authored
246 def _all_autoload_paths
247 @_all_autoload_paths ||= (config.autoload_paths + config.eager_load_paths + config.autoload_once_paths).uniq
248 end
249
250 def _all_load_paths
251 @_all_load_paths ||= (config.paths.load_paths + _all_autoload_paths).uniq
788fce2 @josevalim Create configurable modules and ensure that they are added only on direc...
josevalim authored
252 end
7fcf859 @josevalim Massive cleanup in Railties and load stack.
josevalim authored
253 end
6324eee @jeremy plugin rails/init.rb deprecation message
jeremy authored
254 end
Something went wrong with that request. Please try again.