aboutsummaryrefslogtreecommitdiffstats
path: root/railties/lib
diff options
context:
space:
mode:
Diffstat (limited to 'railties/lib')
-rw-r--r--railties/lib/rails/application.rb104
-rw-r--r--railties/lib/rails/application/bootstrap.rb7
-rw-r--r--railties/lib/rails/application/configuration.rb47
-rw-r--r--railties/lib/rails/application/finisher.rb44
-rw-r--r--railties/lib/rails/application/routes_reloader.rb10
-rw-r--r--railties/lib/rails/engine.rb6
-rw-r--r--railties/lib/rails/generators/app_base.rb2
-rw-r--r--railties/lib/rails/railtie/configuration.rb12
8 files changed, 169 insertions, 63 deletions
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index f5f47acfbc..0b8eac8a8b 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -33,6 +33,25 @@ module Rails
#
# The Application is also responsible for building the middleware stack.
#
+ # == Booting process
+ #
+ # The application is also responsible for setting up and executing the booting
+ # process. From the moment you require "config/application.rb" in your app,
+ # the booting process goes like this:
+ #
+ # 1) require "config/boot.rb" to setup load paths
+ # 2) require railties and engines
+ # 3) Define Rails.application as "class MyApp::Application < Rails::Application"
+ # 4) Run config.before_configuration callbacks
+ # 5) Load config/environments/ENV.rb
+ # 6) Run config.before_initialize callbacks
+ # 7) Run Railtie#initializer defined by railties, engines and application.
+ # One by one, each engine sets up its load paths, routes, locales and so on.
+ # 8) Runs all registered config/initializers/*, executing the engines one first
+ # 9) Build the middleware stack and run to_prepare callbacks
+ # 10) Run config.before_eager_load and eager_load if cache classes is true
+ # 11) Run config.after_initialize callbacks
+ #
class Application < Engine
autoload :Bootstrap, 'rails/application/bootstrap'
autoload :Configuration, 'rails/application/configuration'
@@ -52,12 +71,14 @@ module Rails
attr_accessor :assets, :sandbox
alias_method :sandbox?, :sandbox
+ attr_reader :reloaders
delegate :default_url_options, :default_url_options=, :to => :routes
def initialize
super
@initialized = false
+ @reloaders = []
end
# This method is called just after an application inherits from Rails::Application,
@@ -83,27 +104,83 @@ module Rails
require environment if environment
end
+ # Reload application routes regardless if they changed or not.
def reload_routes!
routes_reloader.reload!
end
- def routes_reloader
+ def routes_reloader #:nodoc:
@routes_reloader ||= RoutesReloader.new
end
- def initialize!(group=:default)
+ # A routes reloader hook that is used to setup to_prepare callbacks.
+ # A plugin may override this if they desire to provide a more
+ # exquisite route reloading.
+ # :api: plugin
+ def set_routes_reloader_hook
+ reloader = routes_reloader
+ hook = lambda { reloader.execute_if_updated }
+ hook.call
+ self.reloaders << reloader
+ ActionDispatch::Reloader.to_prepare(&hook)
+ end
+
+ # An app dependencies hook that is used to setup to_cleanup callbacks.
+ # A plugin may override this if they desire to provide a more exquisite app reloading.
+ # :api: plugin
+ def set_dependencies_hook
+ callback = lambda do
+ ActiveSupport::DescendantsTracker.clear
+ ActiveSupport::Dependencies.clear
+ end
+
+ if config.reload_classes_only_on_change
+ reloader = ActiveSupport::FileUpdateChecker.new(watchable_args, true, &callback)
+ self.reloaders << reloader
+ # We need to set a to_prepare callback regardless of the reloader result, i.e.
+ # models should be reloaded if any of the reloaders (i18n, routes) were updated.
+ ActionDispatch::Reloader.to_prepare(:prepend => true, &callback)
+ else
+ ActionDispatch::Reloader.to_cleanup(&callback)
+ end
+ end
+
+ # Returns an array of file paths appended with a hash of directories-extensions
+ # suitable for ActiveSupport::FileUpdateChecker API.
+ def watchable_args
+ files = []
+ files.concat config.watchable_files
+
+ dirs = {}
+ dirs.merge! config.watchable_dirs
+ ActiveSupport::Dependencies.autoload_paths.each do |path|
+ dirs[path.to_s] = [:rb]
+ end
+
+ files << dirs
+ end
+
+ # Initialize the application passing the given group. By default, the
+ # group is :default but sprockets precompilation passes group equals
+ # to assets if initialize_on_precompile is false to avoid booting the
+ # whole app.
+ def initialize!(group=:default) #:nodoc:
raise "Application has been already initialized." if @initialized
run_initializers(group, self)
@initialized = true
self
end
+ # Load the application and its railties tasks and invoke the registered hooks.
+ # Check <tt>Rails::Railtie.rake_tasks</tt> for more info.
def load_tasks(app=self)
initialize_tasks
super
self
end
+ # Load the application console and invoke the registered hooks.
+ # Check <tt>Rails::Railtie.console</tt> for more info.
def load_console(app=self)
initialize_console
super
@@ -129,7 +206,8 @@ module Rails
})
end
- def ordered_railties
+ # Returns the ordered railties for this application considering railties_order.
+ def ordered_railties #:nodoc:
@ordered_railties ||= begin
order = config.railties_order.map do |railtie|
if railtie == :main_app
@@ -151,13 +229,13 @@ module Rails
end
end
- def initializers
+ def initializers #:nodoc:
Bootstrap.initializers_for(self) +
super +
Finisher.initializers_for(self)
end
- def config
+ def config #:nodoc:
@config ||= Application::Configuration.new(find_root_with_flag("config.ru", Dir.pwd))
end
@@ -165,7 +243,7 @@ module Rails
self
end
- def helpers_paths
+ def helpers_paths #:nodoc:
config.helpers_paths
end
@@ -173,6 +251,10 @@ module Rails
alias :build_middleware_stack :app
+ def reload_dependencies?
+ config.reload_classes_only_on_change != true || reloaders.map(&:updated?).any?
+ end
+
def default_middleware_stack
ActionDispatch::MiddlewareStack.new.tap do |middleware|
if rack_cache = config.action_controller.perform_caching && config.action_dispatch.rack_cache
@@ -202,7 +284,11 @@ module Rails
middleware.use ::Rack::Sendfile, config.action_dispatch.x_sendfile_header
end
- middleware.use ::ActionDispatch::Reloader unless config.cache_classes
+ unless config.cache_classes
+ app = self
+ middleware.use ::ActionDispatch::Reloader, lambda { app.reload_dependencies? }
+ end
+
middleware.use ::ActionDispatch::Callbacks
middleware.use ::ActionDispatch::Cookies
@@ -222,7 +308,7 @@ module Rails
end
end
- def initialize_tasks
+ def initialize_tasks #:nodoc:
self.class.rake_tasks do
require "rails/tasks"
task :environment do
@@ -232,7 +318,7 @@ module Rails
end
end
- def initialize_console
+ def initialize_console #:nodoc:
require "pp"
require "rails/console/app"
require "rails/console/helpers"
diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb
index 1ae90056d9..e189009cc5 100644
--- a/railties/lib/rails/application/bootstrap.rb
+++ b/railties/lib/rails/application/bootstrap.rb
@@ -59,13 +59,6 @@ module Rails
end
end
- initializer :set_clear_dependencies_hook, :group => :all do
- ActionDispatch::Reloader.to_cleanup do
- ActiveSupport::DescendantsTracker.clear
- ActiveSupport::Dependencies.clear
- end
- end
-
# Sets the dependency loading mechanism.
# TODO: Remove files from the $" and always use require.
initializer :initialize_dependency_mechanism, :group => :all do
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index e95b0f5495..39d66ecc31 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -7,11 +7,11 @@ module Rails
class Configuration < ::Rails::Engine::Configuration
attr_accessor :allow_concurrency, :asset_host, :asset_path, :assets,
:cache_classes, :cache_store, :consider_all_requests_local,
- :dependency_loading, :filter_parameters,
- :force_ssl, :helpers_paths, :logger, :log_tags, :preload_frameworks,
- :reload_plugins, :secret_token, :serve_static_assets,
- :ssl_options, :static_cache_control, :session_options,
- :time_zone, :whiny_nils, :railties_order
+ :dependency_loading, :filter_parameters, :force_ssl, :helpers_paths,
+ :initializers_paths, :logger, :log_tags, :preload_frameworks,
+ :railties_order, :relative_url_root, :reload_plugins, :secret_token,
+ :serve_static_assets, :ssl_options, :static_cache_control, :session_options,
+ :time_zone, :reload_classes_only_on_change, :whiny_nils
attr_writer :log_level
attr_reader :encoding
@@ -19,23 +19,26 @@ module Rails
def initialize(*)
super
self.encoding = "utf-8"
- @allow_concurrency = false
- @consider_all_requests_local = false
- @filter_parameters = []
- @helpers_paths = []
- @dependency_loading = true
- @serve_static_assets = true
- @static_cache_control = nil
- @force_ssl = false
- @ssl_options = {}
- @session_store = :cookie_store
- @session_options = {}
- @time_zone = "UTC"
- @log_level = nil
- @middleware = app_middleware
- @generators = app_generators
- @cache_store = [ :file_store, "#{root}/tmp/cache/" ]
- @railties_order = [:all]
+ @allow_concurrency = false
+ @consider_all_requests_local = false
+ @filter_parameters = []
+ @helpers_paths = []
+ @dependency_loading = true
+ @serve_static_assets = true
+ @static_cache_control = nil
+ @force_ssl = false
+ @ssl_options = {}
+ @session_store = :cookie_store
+ @session_options = {}
+ @time_zone = "UTC"
+ @log_level = nil
+ @middleware = app_middleware
+ @generators = app_generators
+ @cache_store = [ :file_store, "#{root}/tmp/cache/" ]
+ @railties_order = [:all]
+ @initializers_paths = []
+ @relative_url_root = ENV["RAILS_RELATIVE_URL_ROOT"]
+ @reload_classes_only_on_change = true
@assets = ActiveSupport::OrderedOptions.new
@assets.enabled = false
diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb
index fc7d205a6f..e000f6ef3a 100644
--- a/railties/lib/rails/application/finisher.rb
+++ b/railties/lib/rails/application/finisher.rb
@@ -4,6 +4,10 @@ module Rails
include Initializable
$rails_rake_task = nil
+ initializer :load_config_initializers do
+ config.initializers_paths.each { |init| load(init) }
+ end
+
initializer :add_generator_templates do
config.generators.templates.unshift(*paths["lib/templates"].existent)
end
@@ -20,12 +24,6 @@ module Rails
end
end
- initializer :add_to_prepare_blocks do
- config.to_prepare_blocks.each do |block|
- ActionDispatch::Reloader.to_prepare(&block)
- end
- end
-
initializer :add_builtin_route do |app|
if Rails.env.development?
app.routes.append do
@@ -38,14 +36,22 @@ module Rails
build_middleware_stack
end
- initializer :run_prepare_callbacks do
- ActionDispatch::Reloader.prepare!
- end
-
initializer :define_main_app_helper do |app|
app.routes.define_mounted_helper(:main_app)
end
+ initializer :add_to_prepare_blocks do
+ config.to_prepare_blocks.each do |block|
+ ActionDispatch::Reloader.to_prepare(&block)
+ end
+ end
+
+ # This needs to happen before eager load so it happens
+ # in exactly the same point regardless of config.cache_classes
+ initializer :run_prepare_callbacks do
+ ActionDispatch::Reloader.prepare!
+ end
+
initializer :eager_load! do
if config.cache_classes && !$rails_rake_task
ActiveSupport.run_load_hooks(:before_eager_load, self)
@@ -53,17 +59,21 @@ module Rails
end
end
+ # All initialization is done, including eager loading in production
initializer :finisher_hook do
ActiveSupport.run_load_hooks(:after_initialize, self)
end
- # Force routes to be loaded just at the end and add it to to_prepare callbacks
- # This needs to be after the finisher hook to ensure routes added in the hook
- # are still loaded.
- initializer :set_routes_reloader do |app|
- reloader = lambda { app.routes_reloader.execute_if_updated }
- reloader.call
- ActionDispatch::Reloader.to_prepare(&reloader)
+ # Set app reload just after the finisher hook to ensure
+ # routes added in the hook are still loaded.
+ initializer :set_routes_reloader_hook do |app|
+ app.set_routes_reloader_hook
+ end
+
+ # Set app reload just after the finisher hook to ensure
+ # paths added in the hook are still loaded.
+ initializer :set_dependencies_hook, :group => :all do |app|
+ app.set_dependencies_hook
end
# Disable dependency loading during request cycle
diff --git a/railties/lib/rails/application/routes_reloader.rb b/railties/lib/rails/application/routes_reloader.rb
index 1d1f5e1b06..460b84dfd9 100644
--- a/railties/lib/rails/application/routes_reloader.rb
+++ b/railties/lib/rails/application/routes_reloader.rb
@@ -1,10 +1,14 @@
+require "active_support/core_ext/module/delegation"
+
module Rails
class Application
- class RoutesReloader < ::ActiveSupport::FileUpdateChecker
+ class RoutesReloader
attr_reader :route_sets
- def initialize
- super([]) { reload! }
+ delegate :paths, :execute_if_updated, :updated?, :to => :@updater
+
+ def initialize(updater=ActiveSupport::FileUpdateChecker)
+ @updater = updater.new([]) { reload! }
@route_sets = []
end
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 5c1af99fe2..86efc7332c 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -583,10 +583,8 @@ module Rails
end
end
- initializer :load_config_initializers do
- config.paths["config/initializers"].existent.sort.each do |initializer|
- load(initializer)
- end
+ initializer :append_config_initializers do |app|
+ app.config.initializers_paths.concat config.paths["config/initializers"].existent.sort
end
initializer :engines_blank_point do
diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index e3d22e81fb..0bd39cb2cd 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -194,7 +194,7 @@ module Rails
def assets_gemfile_entry
return if options[:skip_sprockets]
- <<-GEMFILE.strip_heredoc
+ <<-GEMFILE.strip_heredoc.gsub(/^[ \t]*$/, '')
# Gems used only for assets and not required
# in production environments by default.
group :assets do
diff --git a/railties/lib/rails/railtie/configuration.rb b/railties/lib/rails/railtie/configuration.rb
index f888684117..cf9e4ad500 100644
--- a/railties/lib/rails/railtie/configuration.rb
+++ b/railties/lib/rails/railtie/configuration.rb
@@ -7,6 +7,18 @@ module Rails
@@options ||= {}
end
+ # Add files that should be watched for change.
+ def watchable_files
+ @@watchable_files ||= []
+ end
+
+ # Add directories that should be watched for change.
+ # The key of the hashes should be directories and the values should
+ # be an array of extensions to match in each directory.
+ def watchable_dirs
+ @@watchable_dirs ||= {}
+ end
+
# This allows you to modify the application's middlewares from Engines.
#
# All operations you run on the app_middleware will be replayed on the