diff options
33 files changed, 215 insertions, 109 deletions
diff --git a/actionmailer/lib/action_mailer.rb b/actionmailer/lib/action_mailer.rb index 32e6183ff6..cfbe2f1cbd 100644 --- a/actionmailer/lib/action_mailer.rb +++ b/actionmailer/lib/action_mailer.rb @@ -35,7 +35,10 @@ require 'active_support/lazy_load_hooks' module ActionMailer extend ::ActiveSupport::Autoload - autoload :Collector + eager_autoload do + autoload :Collector + end + autoload :Base autoload :DeliveryMethods autoload :MailHelper diff --git a/actionmailer/lib/action_mailer/railtie.rb b/actionmailer/lib/action_mailer/railtie.rb index 5c03a29f0f..8679096735 100644 --- a/actionmailer/lib/action_mailer/railtie.rb +++ b/actionmailer/lib/action_mailer/railtie.rb @@ -5,6 +5,7 @@ require "abstract_controller/railties/routes_helpers" module ActionMailer class Railtie < Rails::Railtie config.action_mailer = ActiveSupport::OrderedOptions.new + config.eager_load_namespaces << ActionMailer initializer "action_mailer.logger" do ActiveSupport.on_load(:action_mailer) { self.logger ||= Rails.logger } diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index ceb90f8cee..31df9d605c 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -48,6 +48,12 @@ module ActionController eager_autoload do autoload :RecordIdentifier end + + def self.eager_load! + super + ActionController::Caching.eager_load! + HTML.eager_load! + end end # All of these simply register additional autoloads diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index 851a2c4aee..3ecc105e22 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -9,6 +9,8 @@ module ActionController class Railtie < Rails::Railtie #:nodoc: config.action_controller = ActiveSupport::OrderedOptions.new + config.eager_load_namespaces << ActionController + initializer "action_controller.assets_config", :group => :all do |app| app.config.action_controller.assets_dir ||= app.config.paths["public"].first end diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb index b382997052..57b4678add 100644 --- a/actionpack/lib/action_dispatch.rb +++ b/actionpack/lib/action_dispatch.rb @@ -38,9 +38,11 @@ module ActionDispatch class IllegalStateError < StandardError end - autoload_under 'http' do - autoload :Request - autoload :Response + eager_autoload do + autoload_under 'http' do + autoload :Request + autoload :Response + end end autoload_under 'middleware' do diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb index 5aad8dd23a..ccc0435a39 100644 --- a/actionpack/lib/action_dispatch/railtie.rb +++ b/actionpack/lib/action_dispatch/railtie.rb @@ -25,6 +25,8 @@ module ActionDispatch 'X-Content-Type-Options' => 'nosniff' } + config.eager_load_namespaces << ActionDispatch + initializer "action_dispatch.configure" do |app| ActionDispatch::Http::URL.tld_length = app.config.action_dispatch.tld_length ActionDispatch::Request.ignore_accept_header = app.config.action_dispatch.ignore_accept_header diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb index 4bd72c5520..9d11c284f5 100644 --- a/actionpack/lib/action_view.rb +++ b/actionpack/lib/action_view.rb @@ -38,7 +38,6 @@ module ActionView autoload :PathSet autoload :Template - autoload_under "renderer" do autoload :Renderer autoload :AbstractRenderer @@ -77,6 +76,11 @@ module ActionView autoload :TestCase ENCODING_FLAG = '#.*coding[:=]\s*(\S+)[ \t]*' + + def self.eager_load! + super + ActionView::Template.eager_load! + end end require 'active_support/core_ext/string/output_safety' diff --git a/actionpack/lib/action_view/railtie.rb b/actionpack/lib/action_view/railtie.rb index 9f5e3be454..2d36deaa78 100644 --- a/actionpack/lib/action_view/railtie.rb +++ b/actionpack/lib/action_view/railtie.rb @@ -9,6 +9,8 @@ module ActionView config.action_view.javascript_expansions = { :defaults => %w(jquery jquery_ujs) } config.action_view.embed_authenticity_token_in_remote_forms = false + config.eager_load_namespaces << ActionView + initializer "action_view.embed_authenticity_token_in_remote_forms" do |app| ActiveSupport.on_load(:action_view) do ActionView::Helpers::FormTagHelper.embed_authenticity_token_in_remote_forms = diff --git a/activemodel/lib/active_model.rb b/activemodel/lib/active_model.rb index ec2d734647..d1cc19ec6b 100644 --- a/activemodel/lib/active_model.rb +++ b/activemodel/lib/active_model.rb @@ -34,7 +34,6 @@ module ActiveModel autoload :Conversion autoload :Dirty autoload :EachValidator, 'active_model/validator' - autoload :Errors autoload :Lint autoload :MassAssignmentSecurity autoload :Model @@ -49,11 +48,22 @@ module ActiveModel autoload :Validations autoload :Validator + eager_autoload do + autoload :Errors + end + module Serializers extend ActiveSupport::Autoload - autoload :JSON - autoload :Xml + eager_autoload do + autoload :JSON + autoload :Xml + end + end + + def eager_load! + super + ActiveModel::Serializer.eager_load! end end diff --git a/activemodel/lib/active_model/railtie.rb b/activemodel/lib/active_model/railtie.rb index 63ffe5db63..f239758b35 100644 --- a/activemodel/lib/active_model/railtie.rb +++ b/activemodel/lib/active_model/railtie.rb @@ -1,2 +1,8 @@ require "active_model" -require "rails"
\ No newline at end of file +require "rails" + +module ActiveModel + class Railtie < Rails::Railtie + config.eager_load_namespaces << ActiveModel + end +end
\ No newline at end of file diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb index 39427bc296..fa94f6a941 100644 --- a/activerecord/lib/active_record.rb +++ b/activerecord/lib/active_record.rb @@ -160,6 +160,15 @@ module ActiveRecord autoload :TestCase autoload :TestFixtures, 'active_record/fixtures' + + def self.eager_load! + super + ActiveRecord::Locking.eager_load! + ActiveRecord::Scoping.eager_load! + ActiveRecord::Associations.eager_load! + ActiveRecord::AttributeMethods.eager_load! + ActiveRecord::ConnectionAdapters.eager_load! + end end ActiveSupport.on_load(:active_record) do diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb index 672d9a4246..ecf8547e67 100644 --- a/activerecord/lib/active_record/railtie.rb +++ b/activerecord/lib/active_record/railtie.rb @@ -29,8 +29,11 @@ module ActiveRecord 'ActiveRecord::RecordNotSaved' => :unprocessable_entity ) + config.active_record.use_schema_cache_dump = true + config.eager_load_namespaces << ActiveRecord + rake_tasks do require "active_record/base" load "active_record/railties/databases.rake" diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index 56d6676961..41d77ab6c1 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -37,7 +37,6 @@ module ActiveSupport autoload :LogSubscriber autoload :Notifications - # TODO: Narrow this list down eager_autoload do autoload :BacktraceCleaner autoload :BasicObject @@ -55,12 +54,12 @@ module ActiveSupport autoload :OptionMerger autoload :OrderedHash autoload :OrderedOptions - autoload :Rescuable autoload :StringInquirer autoload :TaggedLogging autoload :XmlMini end + autoload :Rescuable autoload :SafeBuffer, "active_support/core_ext/string/output_safety" autoload :TestCase end diff --git a/activesupport/lib/active_support/dependencies/autoload.rb b/activesupport/lib/active_support/dependencies/autoload.rb index 4045db3232..df490ae298 100644 --- a/activesupport/lib/active_support/dependencies/autoload.rb +++ b/activesupport/lib/active_support/dependencies/autoload.rb @@ -1,52 +1,78 @@ require "active_support/inflector/methods" module ActiveSupport + # Autoload and eager load conveniences for your library. + # + # This module allows you to define autoloads based on + # Rails conventions (i.e. no need to define the path + # it is automatically guessed based on the filename) + # and also define a set of constants that needs to be + # eager loaded: + # + # module MyLib + # extend ActiveSupport::Autoload + # + # autoload :Model + # + # eager_autoload do + # autoload :Cache + # end + # end + # + # Then your library can be eager loaded by simply calling: + # + # MyLib.eager_load! + # module Autoload - @@autoloads = {} - @@under_path = nil - @@at_path = nil - @@eager_autoload = false + def self.extended(base) + base.class_eval do + @_autoloads = {} + @_under_path = nil + @_at_path = nil + @_eager_autoload = false + end + end - def autoload(const_name, path = @@at_path) + def autoload(const_name, path = @_at_path) unless path - full = [name, @@under_path, const_name.to_s, path].compact.join("::") + full = [name, @_under_path, const_name.to_s, path].compact.join("::") path = Inflector.underscore(full) end - if @@eager_autoload - @@autoloads[const_name] = path + if @_eager_autoload + @_autoloads[const_name] = path end super const_name, path end def autoload_under(path) - @@under_path, old_path = path, @@under_path + @_under_path, old_path = path, @_under_path yield ensure - @@under_path = old_path + @_under_path = old_path end def autoload_at(path) - @@at_path, old_path = path, @@at_path + @_at_path, old_path = path, @_at_path yield ensure - @@at_path = old_path + @_at_path = old_path end def eager_autoload - old_eager, @@eager_autoload = @@eager_autoload, true + old_eager, @_eager_autoload = @_eager_autoload, true yield ensure - @@eager_autoload = old_eager + @_eager_autoload = old_eager end - def self.eager_autoload! - @@autoloads.values.each { |file| require file } + def eager_load! + @_autoloads.values.each { |file| require file } end def autoloads - @@autoloads + @_autoloads end end end diff --git a/activesupport/lib/active_support/railtie.rb b/activesupport/lib/active_support/railtie.rb index 30ac881090..aa8d408da9 100644 --- a/activesupport/lib/active_support/railtie.rb +++ b/activesupport/lib/active_support/railtie.rb @@ -5,6 +5,8 @@ module ActiveSupport class Railtie < Rails::Railtie config.active_support = ActiveSupport::OrderedOptions.new + config.eager_load_namespaces << ActiveSupport + initializer "active_support.deprecation_behavior" do |app| if deprecation = app.config.active_support.deprecation ActiveSupport::Deprecation.behavior = deprecation diff --git a/activesupport/test/autoload.rb b/activesupport/test/autoload_test.rb index 5d8026a9ca..7d02d835a8 100644 --- a/activesupport/test/autoload.rb +++ b/activesupport/test/autoload_test.rb @@ -28,15 +28,6 @@ class TestAutoloadModule < ActiveSupport::TestCase assert_nothing_raised { ::Fixtures::Autoload::SomeClass } end - test ":eager constants can be triggered via ActiveSupport::Autoload.eager_autoload!" do - module ::Fixtures::Autoload - autoload :SomeClass, "fixtures/autoload/some_class" - end - ActiveSupport::Autoload.eager_autoload! - assert $LOADED_FEATURES.include?("fixtures/autoload/some_class.rb") - assert_nothing_raised { ::Fixtures::Autoload::SomeClass } - end - test "the location of autoloaded constants defaults to :name.underscore" do module ::Fixtures::Autoload autoload :SomeClass @@ -51,8 +42,7 @@ class TestAutoloadModule < ActiveSupport::TestCase autoload :SomeClass end - ActiveSupport::Autoload.eager_autoload! - assert $LOADED_FEATURES.include?("fixtures/autoload/some_class.rb") + ::Fixtures::Autoload.eager_load! assert_nothing_raised { ::Fixtures::Autoload::SomeClass } end diff --git a/guides/source/configuring.textile b/guides/source/configuring.textile index c29b70ad5b..27eaf1cbc5 100644 --- a/guides/source/configuring.textile +++ b/guides/source/configuring.textile @@ -50,8 +50,6 @@ config.after_initialize do end </ruby> -* +config.allow_concurrency+ should be true to allow concurrent (threadsafe) action processing. False by default. You probably don't want to call this one directly, though, because a series of other adjustments need to be made for threadsafe mode to work properly. Can also be enabled with +threadsafe!+. - * +config.asset_host+ sets the host for the assets. Useful when CDNs are used for hosting assets, or when you want to work around the concurrency constraints builtin in browsers using different domain aliases. Shorter version of +config.action_controller.asset_host+. * +config.asset_path+ lets you decorate asset paths. This can be a callable, a string, or be +nil+ which is the default. For example, the normal path for +blog.js+ would be +/javascripts/blog.js+, let that absolute path be +path+. If +config.asset_path+ is a callable, Rails calls it when generating asset paths passing +path+ as argument. If +config.asset_path+ is a string, it is expected to be a +sprintf+ format string with a +%s+ where +path+ will get inserted. In either case, Rails outputs the decorated path. Shorter version of +config.action_controller.asset_path+. @@ -89,6 +87,10 @@ end * +config.dependency_loading+ is a flag that allows you to disable constant autoloading setting it to false. It only has effect if +config.cache_classes+ is true, which it is by default in production mode. This flag is set to false by +config.threadsafe!+. +* +config.eager_load+ when true, eager loads all registered `config.eager_load_namespaces`. This includes your application, engines, Rails frameworks and any other registered namespace. + +* +config.eager_load_namespaces+ registers namespaces that are eager loaded when +config.eager_load+ is true. All namespaces in the list must respond to the +eager_load!+ method. + * +config.eager_load_paths+ accepts an array of paths from which Rails will eager load on boot if cache classes is enabled. Defaults to every folder in the +app+ directory of the application. * +config.encoding+ sets up the application-wide encoding. Defaults to UTF-8. @@ -109,8 +111,6 @@ end * +config.middleware+ allows you to configure the application's middleware. This is covered in depth in the "Configuring Middleware":#configuring-middleware section below. -* +config.preload_frameworks+ enables or disables preloading all frameworks at startup. Enabled by +config.threadsafe!+. Defaults to +nil+, so is disabled. - * +config.queue+ configures a different queue implementation for the application. Defaults to +Rails::Queueing::Queue+. Note that, if the default queue is changed, the default +queue_consumer+ is not going to be initialized, it is up to the new queue implementation to handle starting and shutting down its own consumer(s). * +config.queue_consumer+ configures a different consumer implementation for the default queue. Defaults to +Rails::Queueing::ThreadedConsumer+. @@ -129,10 +129,6 @@ config.session_store :my_custom_store This custom store must be defined as +ActionDispatch::Session::MyCustomStore+. In addition to symbols, they can also be objects implementing a certain API, like +ActiveRecord::SessionStore+, in which case no special namespace is required. -* +config.threadsafe!+ enables +allow_concurrency+, +cache_classes+, +dependency_loading+ and +preload_frameworks+ to make the application threadsafe. - -WARNING: Threadsafe operation is incompatible with the normal workings of development mode Rails. In particular, automatic dependency loading and class reloading are automatically disabled when you call +config.threadsafe!+. - * +config.time_zone+ sets the default time zone for the application and enables time zone awareness for Active Record. * +config.whiny_nils+ enables or disables warnings when a certain set of methods are invoked on +nil+ and it does not respond to them. Defaults to true in development and test environments. @@ -203,7 +199,7 @@ Every Rails application comes with a standard set of middleware which it uses in * +ActionDispatch::SSL+ forces every request to be under HTTPS protocol. Will be available if +config.force_ssl+ is set to +true+. Options passed to this can be configured by using +config.ssl_options+. * +ActionDispatch::Static+ is used to serve static assets. Disabled if +config.serve_static_assets+ is +true+. -* +Rack::Lock+ wraps the app in mutex so it can only be called by a single thread at a time. Only enabled if +config.action_controller.allow_concurrency+ is set to +false+, which it is by default. +* +Rack::Lock+ wraps the app in mutex so it can only be called by a single thread at a time. Only enabled when +config.cache_classes_+ is +false+. * +ActiveSupport::Cache::Strategy::LocalCache+ serves as a basic memory backed cache. This cache is not thread safe and is intended only for serving as a temporary memory cache for a single thread. * +Rack::Runtime+ sets an +X-Runtime+ header, containing the time (in seconds) taken to execute the request. * +Rails::Rack::Logger+ notifies the logs that the request has began. After request is complete, flushes all the logs. @@ -656,8 +652,6 @@ Serves as a placeholder so that +:load_environment_config+ can be defined to run *+load_active_support+* Requires +active_support/dependencies+ which sets up the basis for Active Support. Optionally requires +active_support/all+ if +config.active_support.bare+ is un-truthful, which is the default. -*+preload_frameworks+* Loads all autoload dependencies of Rails automatically if +config.preload_frameworks+ is +true+ or "truthful". By default this configuration option is disabled. In Rails, when internal classes are referenced for the first time they are autoloaded. +:preload_frameworks+ loads all of this at once on initialization. - *+initialize_logger+* Initializes the logger (an +ActiveSupport::BufferedLogger+ object) for the application and makes it accessible at +Rails.logger+, provided that no initializer inserted before this point has defined +Rails.logger+. *+initialize_cache+* If +Rails.cache+ isn't set yet, initializes the cache by referencing the value in +config.cache_store+ and stores the outcome as +Rails.cache+. If this object responds to the +middleware+ method, its middleware is inserted before +Rack::Runtime+ in the middleware stack. @@ -752,13 +746,13 @@ The error occurred while evaluating nil.each *+build_middleware_stack+* Builds the middleware stack for the application, returning an object which has a +call+ method which takes a Rack environment object for the request. -*+eager_load!+* If +config.cache_classes+ is true, runs the +config.before_eager_load+ hooks and then calls +eager_load!+ which will load all the Ruby files from +config.eager_load_paths+. +*+eager_load!+* If +config.eager_load+ is true, runs the +config.before_eager_load+ hooks and then calls +eager_load!+ which will load all +config.eager_load_namespaces+. *+finisher_hook+* Provides a hook for after the initialization of process of the application is complete, as well as running all the +config.after_initialize+ blocks for the application, railties and engines. *+set_routes_reloader+* Configures Action Dispatch to reload the routes file using +ActionDispatch::Callbacks.to_prepare+. -*+disable_dependency_loading+* Disables the automatic dependency loading if the +config.cache_classes+ is set to true and +config.dependency_loading+ is set to false. +*+disable_dependency_loading+* Disables the automatic dependency loading if the +config.eager_load+ is set to true. h3. Database pooling diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 851f41249a..fea18b5f47 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -5,6 +5,8 @@ default_url_options[:script_name] to set proper application's mount point by yourself. *Piotr Sarnacki* +* `config.threadsafe!` is deprecated in favor of `config.eager_load` which provides a more fine grained control on what is eager loaded *José Valim* + * The migration generator will now produce AddXXXToYYY/RemoveXXXFromYYY migrations with references statements, for instance rails g migration AddReferencesToProducts user:references supplier:references{polymorphic} diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 3531728421..ae872f2bb0 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -16,7 +16,7 @@ module Rails # # Besides providing the same configuration as Rails::Engine and Rails::Railtie, # the application object has several specific configurations, for example - # "allow_concurrency", "cache_classes", "consider_all_requests_local", "filter_parameters", + # "cache_classes", "consider_all_requests_local", "filter_parameters", # "logger" and so forth. # # Check Rails::Application::Configuration to see them all. @@ -216,8 +216,9 @@ module Rails railties.each { |r| r.run_tasks_blocks(app) } super require "rails/tasks" + config = self.config task :environment do - $rails_rake_task = true + config.eager_load = false require_environment! end end @@ -296,7 +297,7 @@ module Rails middleware.use ::ActionDispatch::Static, paths["public"].first, config.static_cache_control end - middleware.use ::Rack::Lock unless config.allow_concurrency + middleware.use ::Rack::Lock unless config.cache_classes middleware.use ::Rack::Runtime middleware.use ::Rack::MethodOverride middleware.use ::ActionDispatch::RequestId diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb index e567df7162..a1bc95550b 100644 --- a/railties/lib/rails/application/bootstrap.rb +++ b/railties/lib/rails/application/bootstrap.rb @@ -13,11 +13,18 @@ module Rails require "active_support/all" unless config.active_support.bare end - # Preload all frameworks specified by the Configuration#frameworks. - # Used by Passenger to ensure everything's loaded before forking and - # to avoid autoload race conditions in JRuby. - initializer :preload_frameworks, :group => :all do - ActiveSupport::Autoload.eager_autoload! if config.preload_frameworks + initializer :set_eager_load, :group => :all do + if config.eager_load.nil? + warn <<-INFO +config.eager_load is set to nil. Please update your config/environments/*.rb files accordingly: + + * development - set it to false + * test - set it to false (unless you use a tool that preloads your test environment) + * production - set it to true + +INFO + config.eager_load = config.cache_classes + end end # Initialize the logger early in the stack in case we need to log some deprecation. @@ -60,7 +67,6 @@ module Rails end # Sets the dependency loading mechanism. - # TODO: Remove files from the $" and always use require. initializer :initialize_dependency_mechanism, :group => :all do ActiveSupport::Dependencies.mechanism = config.cache_classes ? :require : :load end diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index 2b36cc9d0d..7f05b2e7e1 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -5,11 +5,11 @@ require 'rails/engine/configuration' module Rails class Application class Configuration < ::Rails::Engine::Configuration - attr_accessor :allow_concurrency, :asset_host, :asset_path, :assets, :autoflush_log, + attr_accessor :asset_host, :asset_path, :assets, :autoflush_log, :cache_classes, :cache_store, :consider_all_requests_local, :console, - :dependency_loading, :exceptions_app, :file_watcher, :filter_parameters, + :eager_load, :exceptions_app, :file_watcher, :filter_parameters, :force_ssl, :helpers_paths, :logger, :log_formatter, :log_tags, - :preload_frameworks, :railties_order, :relative_url_root, :secret_token, + :railties_order, :relative_url_root, :secret_token, :serve_static_assets, :ssl_options, :static_cache_control, :session_options, :time_zone, :reload_classes_only_on_change, :queue, :queue_consumer @@ -20,11 +20,9 @@ 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 @@ -45,6 +43,7 @@ module Rails @log_formatter = ActiveSupport::Logger::SimpleFormatter.new @queue = Rails::Queueing::Queue @queue_consumer = Rails::Queueing::ThreadedConsumer + @eager_load = nil @assets = ActiveSupport::OrderedOptions.new @assets.enabled = false @@ -91,15 +90,12 @@ module Rails end end - # Enable threaded mode. Allows concurrent requests to controller actions and - # multiple database connections. Also disables automatic dependency loading - # after boot, and disables reloading code on every request, as these are - # fundamentally incompatible with thread safety. def threadsafe! - @preload_frameworks = true + ActiveSupport::Deprecation.warn "config.threadsafe! is deprecated. Rails applications " \ + "behave by default as thread safe in production as long as config.cache_classes and " \ + "config.eager_load are set to true" @cache_classes = true - @dependency_loading = false - @allow_concurrency = true + @eager_load = true self end diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index 60aa40b92f..1952a0fc3a 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -50,9 +50,9 @@ module Rails end initializer :eager_load! do - if config.cache_classes && !(defined?($rails_rake_task) && $rails_rake_task) + if config.eager_load ActiveSupport.run_load_hooks(:before_eager_load, self) - eager_load! + config.eager_load_namespaces.each(&:eager_load!) end end @@ -91,7 +91,7 @@ module Rails # Disable dependency loading during request cycle initializer :disable_dependency_loading do - if config.cache_classes && !config.dependency_loading + if config.eager_load ActiveSupport::Dependencies.unhook! end end diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb index 9ef64da3ef..a684129353 100644 --- a/railties/lib/rails/commands/server.rb +++ b/railties/lib/rails/commands/server.rb @@ -87,6 +87,15 @@ module Rails middlewares = [] middlewares << [Rails::Rack::Debugger] if options[:debugger] middlewares << [::Rack::ContentLength] + + # FIXME: add Rack::Lock in the case people are using webrick. + # This is to remain backwards compatible for those who are + # running webrick in production. We should consider removing this + # in development. + if server.name == 'Rack::Handler::WEBrick' + middlewares << [::Rack::Lock] + end + Hash.new(middlewares) end diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 40f35ae5a6..3a5caf9f62 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -339,11 +339,16 @@ module Rails class << self attr_accessor :called_from, :isolated + alias :isolated? :isolated alias :engine_name :railtie_name + delegate :eager_load!, to: :instance + def inherited(base) unless base.abstract_railtie? + Rails::Railtie::Configuration.eager_load_namespaces << base + base.called_from = begin # Remove the line number from backtraces making sure we don't leave anything behind call_stack = caller.map { |p| p.sub(/:\d+.*/, '') } diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt index 2016eb8b05..122e7e2b34 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt @@ -6,6 +6,9 @@ # since you don't have to restart the web server when you make code changes. config.cache_classes = false + # Do not eager load code on boot. + config.eager_load = false + # Show full error reports and disable caching. config.consider_all_requests_local = true config.action_controller.perform_caching = false diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt index 80413be0d3..a627636089 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/production.rb.tt @@ -4,6 +4,12 @@ # Code is not reloaded between requests. config.cache_classes = true + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both thread web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + # Full error reports are disabled and caching is turned on. config.consider_all_requests_local = false config.action_controller.perform_caching = true diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt index 878deb49d7..8ab27eb6e1 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt +++ b/railties/lib/rails/generators/rails/app/templates/config/environments/test.rb.tt @@ -7,6 +7,11 @@ # and recreated between test runs. Don't rely on the data there! config.cache_classes = true + # Do not eager load code on boot. This avoids loading your whole application + # just for the purpose of running a single test. If you are using a tool that + # preloads Rails for running tests, you may have to set it to true. + config.eager_load = false + # Configure static asset server for tests with Cache-Control for performance. config.serve_static_assets = true config.static_cache_control = "public, max-age=3600" diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index 1cb99463cc..fba685c769 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -178,9 +178,6 @@ module Rails @config ||= Railtie::Configuration.new end - def eager_load! - end - def railtie_namespace @railtie_namespace ||= self.class.parents.detect { |n| n.respond_to?(:railtie_namespace) } end diff --git a/railties/lib/rails/railtie/configuration.rb b/railties/lib/rails/railtie/configuration.rb index 1c6b3769a5..9dc8843887 100644 --- a/railties/lib/rails/railtie/configuration.rb +++ b/railties/lib/rails/railtie/configuration.rb @@ -7,6 +7,16 @@ module Rails @@options ||= {} end + # Expose the eager_load_namespaces at "module" level for convenience. + def self.eager_load_namespaces #:nodoc: + @@eager_load_namespaces ||= [] + end + + # All namespaces that are eager loaded + def eager_load_namespaces + @@eager_load_namespaces ||= [] + end + # Add files that should be watched for change. def watchable_files @@watchable_files ||= [] diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index c813defe93..ebdbbaee8b 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -139,22 +139,19 @@ module ApplicationTests assert_instance_of Pathname, Rails.root end - test "marking the application as threadsafe sets the correct config variables" do + test "initialize an eager loaded, cache classes app" do add_to_config <<-RUBY - config.threadsafe! + config.eager_load = true + config.cache_classes = true RUBY require "#{app_path}/config/application" - assert AppTemplate::Application.config.allow_concurrency + assert AppTemplate::Application.initialize! end - test "initialize a threadsafe app" do - add_to_config <<-RUBY - config.threadsafe! - RUBY - + test "application is always added to eager_load namespaces" do require "#{app_path}/config/application" - assert AppTemplate::Application.initialize! + assert AppTemplate::Application, AppTemplate::Application.config.eager_load_namespaces end test "asset_path defaults to nil for application" do @@ -162,10 +159,11 @@ module ApplicationTests assert_equal nil, AppTemplate::Application.config.asset_path end - test "the application can be marked as threadsafe when there are no frameworks" do + test "the application can be eager loaded even when there are no frameworks" do FileUtils.rm_rf("#{app_path}/config/environments") add_to_config <<-RUBY - config.threadsafe! + config.eager_load = true + config.cache_classes = true RUBY use_frameworks [] @@ -175,22 +173,6 @@ module ApplicationTests end end - test "frameworks are not preloaded by default" do - require "#{app_path}/config/environment" - - assert ActionController.autoload?(:Caching) - end - - test "frameworks are preloaded with config.preload_frameworks is set" do - add_to_config <<-RUBY - config.preload_frameworks = true - RUBY - - require "#{app_path}/config/environment" - - assert !ActionView.autoload?(:AssetPaths) - end - test "filter_parameters should be able to set via config.filter_parameters" do add_to_config <<-RUBY config.filter_parameters += [ :foo, 'bar', lambda { |key, value| diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb index 9c9ed0cd6b..34b460d0a7 100644 --- a/railties/test/application/middleware_test.rb +++ b/railties/test/application/middleware_test.rb @@ -87,8 +87,8 @@ module ApplicationTests assert !middleware.include?("ActiveRecord::QueryCache") end - test "removes lock if allow concurrency is set" do - add_to_config "config.allow_concurrency = true" + test "removes lock if cache classes is set" do + add_to_config "config.cache_classes = true" boot! assert !middleware.include?("Rack::Lock") end diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb index a450f90dbf..b05fe3aed5 100644 --- a/railties/test/application/rake_test.rb +++ b/railties/test/application/rake_test.rb @@ -55,6 +55,29 @@ module ApplicationTests assert_match "Doing something...", output end + def test_does_not_explode_when_accessing_a_model_with_eager_load + add_to_config <<-RUBY + config.eager_load = true + + rake_tasks do + task :do_nothing => :environment do + Hello.new.world + end + end + RUBY + + app_file "app/models/hello.rb", <<-RUBY + class Hello + def world + puts "Hello world" + end + end + RUBY + + output = Dir.chdir(app_path){ `rake do_nothing` } + assert_match "Hello world", output + end + def test_code_statistics_sanity assert_match "Code LOC: 5 Test LOC: 0 Code to Test Ratio: 1:0.0", Dir.chdir(app_path){ `rake stats` } diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index 8f04692aef..d89cfba56d 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -12,7 +12,6 @@ require 'bundler/setup' require 'minitest/autorun' require 'active_support/test_case' -# TODO: Remove setting this magic constant RAILS_FRAMEWORK_ROOT = File.expand_path("#{File.dirname(__FILE__)}/../../..") # These files do not require any others and are needed @@ -118,6 +117,7 @@ module TestHelpers end add_to_config <<-RUBY + config.eager_load = false config.secret_token = "3b7cd727ee24e8444053437c36cc66c4" config.session_store :cookie_store, :key => "_myapp_session" config.active_support.deprecation = :log |