aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwycats <wycats@gmail.com>2010-03-07 06:24:30 -0800
committerwycats <wycats@gmail.com>2010-03-07 06:24:30 -0800
commit39d6f9e112f2320d8c2006ee3bcc160cfa761d0a (patch)
tree5c3e4434a5d76ceb7b8fd088d62809ef9a50f025
parenta424f199a9143e7ea451ba6f5e7dc54eb6103988 (diff)
downloadrails-39d6f9e112f2320d8c2006ee3bcc160cfa761d0a.tar.gz
rails-39d6f9e112f2320d8c2006ee3bcc160cfa761d0a.tar.bz2
rails-39d6f9e112f2320d8c2006ee3bcc160cfa761d0a.zip
Make many parts of Rails lazy. In order to facilitate this,
add lazy_load_hooks.rb, which allows us to declare code that should be run at some later time. For instance, this allows us to defer requiring ActiveRecord::Base at boot time purely to apply configuration. Instead, we register a hook that should apply configuration once ActiveRecord::Base is loaded. With these changes, brings down total boot time of a new app to 300ms in production and 400ms in dev. TODO: rename base_hook
-rw-r--r--actionmailer/lib/action_mailer.rb1
-rw-r--r--actionmailer/lib/action_mailer/base.rb2
-rw-r--r--actionmailer/lib/action_mailer/railtie.rb10
-rw-r--r--actionpack/lib/action_controller/base.rb2
-rw-r--r--actionpack/lib/action_controller/railtie.rb14
-rw-r--r--actionpack/lib/action_dispatch/middleware/params_parser.rb1
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/cookie_store.rb1
-rw-r--r--actionpack/lib/action_dispatch/middleware/stack.rb2
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb4
-rw-r--r--actionpack/lib/action_view.rb2
-rw-r--r--actionpack/lib/action_view/base.rb2
-rw-r--r--actionpack/lib/action_view/helpers/active_model_helper.rb8
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb8
-rw-r--r--actionpack/lib/action_view/railtie.rb4
-rw-r--r--actionpack/lib/action_view/test_case.rb1
-rw-r--r--actionpack/test/abstract_unit.rb1
-rw-r--r--activerecord/lib/active_record.rb13
-rwxr-xr-xactiverecord/lib/active_record/base.rb170
-rw-r--r--activerecord/lib/active_record/errors.rb165
-rw-r--r--activerecord/lib/active_record/railtie.rb42
-rw-r--r--activerecord/test/cases/helper.rb1
-rw-r--r--activesupport/lib/active_support.rb3
-rw-r--r--activesupport/lib/active_support/all.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/array/conversions.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/string/interpolation.rb92
-rw-r--r--activesupport/lib/active_support/dependencies/autoload.rb5
-rw-r--r--activesupport/lib/active_support/i18n.rb3
-rw-r--r--activesupport/lib/active_support/lazy_load_hooks.rb25
-rw-r--r--activesupport/lib/active_support/railtie.rb8
-rw-r--r--activesupport/lib/active_support/whiny_nil.rb7
-rw-r--r--activesupport/test/whiny_nil_test.rb2
-rw-r--r--railties/lib/rails/application/routes_reloader.rb2
-rw-r--r--railties/lib/rails/console/helpers.rb4
-rw-r--r--railties/lib/rails/engine.rb4
34 files changed, 299 insertions, 312 deletions
diff --git a/actionmailer/lib/action_mailer.rb b/actionmailer/lib/action_mailer.rb
index 7f5bcad922..43d73e71b9 100644
--- a/actionmailer/lib/action_mailer.rb
+++ b/actionmailer/lib/action_mailer.rb
@@ -34,6 +34,7 @@ require 'active_support/core_ext/array/uniq_by'
require 'active_support/core_ext/module/attr_internal'
require 'active_support/core_ext/module/delegation'
require 'active_support/core_ext/string/inflections'
+require 'active_support/lazy_load_hooks'
module ActionMailer
extend ::ActiveSupport::Autoload
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index 48d6bbc8d9..246816e953 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -291,6 +291,8 @@ module ActionMailer #:nodoc:
:parts_order => [ "text/plain", "text/enriched", "text/html" ]
}.freeze
+ ActionMailer.run_base_hooks(self)
+
class << self
def mailer_name
diff --git a/actionmailer/lib/action_mailer/railtie.rb b/actionmailer/lib/action_mailer/railtie.rb
index c5f18c7911..0182e48425 100644
--- a/actionmailer/lib/action_mailer/railtie.rb
+++ b/actionmailer/lib/action_mailer/railtie.rb
@@ -6,19 +6,21 @@ module ActionMailer
railtie_name :action_mailer
initializer "action_mailer.url_for", :before => :load_environment_config do |app|
- ActionMailer::Base.send(:include, app.routes.url_helpers)
+ ActionMailer.base_hook { include app.routes.url_helpers }
end
require "action_mailer/railties/log_subscriber"
log_subscriber ActionMailer::Railties::LogSubscriber.new
initializer "action_mailer.logger" do
- ActionMailer::Base.logger ||= Rails.logger
+ ActionMailer.base_hook { self.logger ||= Rails.logger }
end
initializer "action_mailer.set_configs" do |app|
- app.config.action_mailer.each do |k,v|
- ActionMailer::Base.send "#{k}=", v
+ ActionMailer.base_hook do
+ app.config.action_mailer.each do |k,v|
+ send "#{k}=", v
+ end
end
end
end
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 78871154c3..d00afa6d4e 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -58,6 +58,8 @@ module ActionController
filter
end
+ ActionController.run_base_hooks(self)
+
end
end
diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb
index e9edf80451..ca03fc62da 100644
--- a/actionpack/lib/action_controller/railtie.rb
+++ b/actionpack/lib/action_controller/railtie.rb
@@ -40,7 +40,7 @@ module ActionController
log_subscriber ActionController::Railties::LogSubscriber.new
initializer "action_controller.logger" do
- ActionController::Base.logger ||= Rails.logger
+ ActionController.base_hook { self.logger ||= Rails.logger }
end
initializer "action_controller.set_configs" do |app|
@@ -51,19 +51,23 @@ module ActionController
ac.stylesheets_dir = paths.public.stylesheets.to_a.first
ac.secret = app.config.cookie_secret
- ActionController::Base.config.replace(ac)
+ ActionController.base_hook { self.config.replace(ac) }
end
initializer "action_controller.initialize_framework_caches" do
- ActionController::Base.cache_store ||= RAILS_CACHE
+ ActionController.base_hook { self.cache_store ||= RAILS_CACHE }
end
initializer "action_controller.set_helpers_path" do |app|
- ActionController::Base.helpers_path = app.config.paths.app.helpers.to_a
+ ActionController.base_hook do
+ self.helpers_path = app.config.paths.app.helpers.to_a
+ end
end
initializer "action_controller.url_helpers" do |app|
- ActionController::Base.extend ::ActionController::Railtie::UrlHelpers.with(app.routes)
+ ActionController.base_hook do
+ extend ::ActionController::Railtie::UrlHelpers.with(app.routes)
+ end
message = "ActionController::Routing::Routes is deprecated. " \
"Instead, use Rails.application.routes"
diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb
index 522982e202..f4c4324fb0 100644
--- a/actionpack/lib/action_dispatch/middleware/params_parser.rb
+++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb
@@ -1,4 +1,3 @@
-require 'active_support/json'
require 'action_dispatch/http/request'
module ActionDispatch
diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
index db64711052..22da82479e 100644
--- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
@@ -1,5 +1,4 @@
require 'active_support/core_ext/hash/keys'
-require 'rack/request'
module ActionDispatch
module Session
diff --git a/actionpack/lib/action_dispatch/middleware/stack.rb b/actionpack/lib/action_dispatch/middleware/stack.rb
index 18a2922fa7..c52c8c0e6a 100644
--- a/actionpack/lib/action_dispatch/middleware/stack.rb
+++ b/actionpack/lib/action_dispatch/middleware/stack.rb
@@ -58,7 +58,7 @@ module ActionDispatch
if lazy_compare?(@klass) && lazy_compare?(middleware)
normalize(@klass) == normalize(middleware)
else
- klass == ActiveSupport::Inflector.constantize(middleware.to_s)
+ klass.name == middleware.to_s
end
end
end
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 52e7b0e77d..52a8df4273 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -1,3 +1,5 @@
+require "active_support/core_ext/hash/except"
+
module ActionDispatch
module Routing
class Mapper
@@ -85,7 +87,7 @@ module ActionDispatch
end
def requirements
- @requirements ||= returning(@options[:constraints] || {}) do |requirements|
+ @requirements ||= (@options[:constraints] || {}).tap do |requirements|
requirements.reverse_merge!(@scope[:constraints]) if @scope[:constraints]
@options.each { |k, v| requirements[k] = v if v.is_a?(Regexp) }
end
diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb
index f5035fe45a..33bf0b8deb 100644
--- a/actionpack/lib/action_view.rb
+++ b/actionpack/lib/action_view.rb
@@ -41,6 +41,7 @@ module ActionView
autoload :Rendering
end
+ autoload :Base
autoload :MissingTemplate, 'action_view/base'
autoload :Resolver, 'action_view/template/resolver'
autoload :PathResolver, 'action_view/template/resolver'
@@ -56,6 +57,5 @@ module ActionView
end
require 'active_support/core_ext/string/output_safety'
-require 'action_view/base'
I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml"
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index 76f9eb2b0d..e88ccc645e 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -177,6 +177,8 @@ module ActionView #:nodoc:
extend ActiveSupport::Memoizable
+ ActionView.run_base_hooks(self)
+
attr_accessor :base_path, :assigns, :template_extension
attr_internal :captures
diff --git a/actionpack/lib/action_view/helpers/active_model_helper.rb b/actionpack/lib/action_view/helpers/active_model_helper.rb
index ed83b8a8b2..4e12cdab54 100644
--- a/actionpack/lib/action_view/helpers/active_model_helper.rb
+++ b/actionpack/lib/action_view/helpers/active_model_helper.rb
@@ -5,9 +5,11 @@ require 'active_support/core_ext/enumerable'
require 'active_support/core_ext/kernel/reporting'
module ActionView
- class Base
- @@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"fieldWithErrors\">#{html_tag}</div>".html_safe }
- cattr_accessor :field_error_proc
+ ActionView.base_hook do
+ class ActionView::Base
+ @@field_error_proc = Proc.new{ |html_tag, instance| "<div class=\"fieldWithErrors\">#{html_tag}</div>".html_safe }
+ cattr_accessor :field_error_proc
+ end
end
module Helpers
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index ace3bcfde3..742e873a49 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -1211,8 +1211,10 @@ module ActionView
end
end
- class Base
- cattr_accessor :default_form_builder
- @@default_form_builder = ::ActionView::Helpers::FormBuilder
+ ActionView.base_hook do
+ class ActionView::Base
+ cattr_accessor :default_form_builder
+ @@default_form_builder = ::ActionView::Helpers::FormBuilder
+ end
end
end
diff --git a/actionpack/lib/action_view/railtie.rb b/actionpack/lib/action_view/railtie.rb
index 03f18ac172..2e5d115630 100644
--- a/actionpack/lib/action_view/railtie.rb
+++ b/actionpack/lib/action_view/railtie.rb
@@ -10,7 +10,9 @@ module ActionView
initializer "action_view.cache_asset_timestamps" do |app|
unless app.config.cache_classes
- ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false
+ ActionView.base_hook do
+ ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false
+ end
end
end
end
diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb
index 72dbead14b..1578ac9479 100644
--- a/actionpack/lib/action_view/test_case.rb
+++ b/actionpack/lib/action_view/test_case.rb
@@ -1,4 +1,5 @@
require 'action_controller/test_case'
+require 'action_view'
module ActionView
class Base
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index d103c4e485..67aa412d3d 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -16,7 +16,6 @@ require 'test/unit'
require 'abstract_controller'
require 'action_controller'
require 'action_view'
-require 'action_view/base'
require 'action_dispatch'
require 'fixture_template'
require 'active_support/dependencies'
diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb
index b79da4565d..5942640c85 100644
--- a/activerecord/lib/active_record.rb
+++ b/activerecord/lib/active_record.rb
@@ -30,7 +30,6 @@ $:.unshift(activemodel_path) if File.directory?(activemodel_path) && !$:.include
require 'active_support'
require 'active_model'
-require 'arel'
module ActiveRecord
extend ActiveSupport::Autoload
@@ -38,8 +37,8 @@ module ActiveRecord
eager_autoload do
autoload :VERSION
- autoload :ActiveRecordError, 'active_record/base'
- autoload :ConnectionNotEstablished, 'active_record/base'
+ autoload :ActiveRecordError, 'active_record/errors'
+ autoload :ConnectionNotEstablished, 'active_record/errors'
autoload :Aggregations
autoload :AssociationPreload
@@ -106,12 +105,16 @@ module ActiveRecord
eager_autoload do
autoload :AbstractAdapter
+ autoload :ConnectionManagement, "active_record/connection_adapters/abstract/connection_pool"
end
end
autoload :TestCase
autoload :TestFixtures, 'active_record/fixtures'
+
+ base_hook do
+ Arel::Table.engine = Arel::Sql::Engine.new(self)
+ end
end
-Arel::Table.engine = Arel::Sql::Engine.new(ActiveRecord::Base)
-I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en.yml'
+I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en.yml' \ No newline at end of file
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 042a67b490..52587ef251 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -13,172 +13,10 @@ require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/string/behavior'
require 'active_support/core_ext/object/singleton_class'
require 'active_support/core_ext/module/delegation'
+require 'arel'
+require 'active_record/errors'
module ActiveRecord #:nodoc:
- # Generic Active Record exception class.
- class ActiveRecordError < StandardError
- end
-
- # Raised when the single-table inheritance mechanism fails to locate the subclass
- # (for example due to improper usage of column that +inheritance_column+ points to).
- class SubclassNotFound < ActiveRecordError #:nodoc:
- end
-
- # Raised when an object assigned to an association has an incorrect type.
- #
- # class Ticket < ActiveRecord::Base
- # has_many :patches
- # end
- #
- # class Patch < ActiveRecord::Base
- # belongs_to :ticket
- # end
- #
- # # Comments are not patches, this assignment raises AssociationTypeMismatch.
- # @ticket.patches << Comment.new(:content => "Please attach tests to your patch.")
- class AssociationTypeMismatch < ActiveRecordError
- end
-
- # Raised when unserialized object's type mismatches one specified for serializable field.
- class SerializationTypeMismatch < ActiveRecordError
- end
-
- # Raised when adapter not specified on connection (or configuration file <tt>config/database.yml</tt> misses adapter field).
- class AdapterNotSpecified < ActiveRecordError
- end
-
- # Raised when Active Record cannot find database adapter specified in <tt>config/database.yml</tt> or programmatically.
- class AdapterNotFound < ActiveRecordError
- end
-
- # Raised when connection to the database could not been established (for example when <tt>connection=</tt> is given a nil object).
- class ConnectionNotEstablished < ActiveRecordError
- end
-
- # Raised when Active Record cannot find record by given id or set of ids.
- class RecordNotFound < ActiveRecordError
- end
-
- # Raised by ActiveRecord::Base.save! and ActiveRecord::Base.create! methods when record cannot be
- # saved because record is invalid.
- class RecordNotSaved < ActiveRecordError
- end
-
- # Raised when SQL statement cannot be executed by the database (for example, it's often the case for MySQL when Ruby driver used is too old).
- class StatementInvalid < ActiveRecordError
- end
-
- # Raised when SQL statement is invalid and the application gets a blank result.
- class ThrowResult < ActiveRecordError
- end
-
- # Parent class for all specific exceptions which wrap database driver exceptions
- # provides access to the original exception also.
- class WrappedDatabaseException < StatementInvalid
- attr_reader :original_exception
-
- def initialize(message, original_exception)
- super(message)
- @original_exception = original_exception
- end
- end
-
- # Raised when a record cannot be inserted because it would violate a uniqueness constraint.
- class RecordNotUnique < WrappedDatabaseException
- end
-
- # Raised when a record cannot be inserted or updated because it references a non-existent record.
- class InvalidForeignKey < WrappedDatabaseException
- end
-
- # Raised when number of bind variables in statement given to <tt>:condition</tt> key (for example, when using +find+ method)
- # does not match number of expected variables.
- #
- # For example, in
- #
- # Location.find :all, :conditions => ["lat = ? AND lng = ?", 53.7362]
- #
- # two placeholders are given but only one variable to fill them.
- class PreparedStatementInvalid < ActiveRecordError
- end
-
- # Raised on attempt to save stale record. Record is stale when it's being saved in another query after
- # instantiation, for example, when two users edit the same wiki page and one starts editing and saves
- # the page before the other.
- #
- # Read more about optimistic locking in ActiveRecord::Locking module RDoc.
- class StaleObjectError < ActiveRecordError
- end
-
- # Raised when association is being configured improperly or
- # user tries to use offset and limit together with has_many or has_and_belongs_to_many associations.
- class ConfigurationError < ActiveRecordError
- end
-
- # Raised on attempt to update record that is instantiated as read only.
- class ReadOnlyRecord < ActiveRecordError
- end
-
- # ActiveRecord::Transactions::ClassMethods.transaction uses this exception
- # to distinguish a deliberate rollback from other exceptional situations.
- # Normally, raising an exception will cause the +transaction+ method to rollback
- # the database transaction *and* pass on the exception. But if you raise an
- # ActiveRecord::Rollback exception, then the database transaction will be rolled back,
- # without passing on the exception.
- #
- # For example, you could do this in your controller to rollback a transaction:
- #
- # class BooksController < ActionController::Base
- # def create
- # Book.transaction do
- # book = Book.new(params[:book])
- # book.save!
- # if today_is_friday?
- # # The system must fail on Friday so that our support department
- # # won't be out of job. We silently rollback this transaction
- # # without telling the user.
- # raise ActiveRecord::Rollback, "Call tech support!"
- # end
- # end
- # # ActiveRecord::Rollback is the only exception that won't be passed on
- # # by ActiveRecord::Base.transaction, so this line will still be reached
- # # even on Friday.
- # redirect_to root_url
- # end
- # end
- class Rollback < ActiveRecordError
- end
-
- # Raised when attribute has a name reserved by Active Record (when attribute has name of one of Active Record instance methods).
- class DangerousAttributeError < ActiveRecordError
- end
-
- # Raised when unknown attributes are supplied via mass assignment.
- class UnknownAttributeError < NoMethodError
- end
-
- # Raised when an error occurred while doing a mass assignment to an attribute through the
- # <tt>attributes=</tt> method. The exception has an +attribute+ property that is the name of the
- # offending attribute.
- class AttributeAssignmentError < ActiveRecordError
- attr_reader :exception, :attribute
- def initialize(message, exception, attribute)
- @exception = exception
- @attribute = attribute
- @message = message
- end
- end
-
- # Raised when there are multiple errors while doing a mass assignment through the +attributes+
- # method. The exception has an +errors+ property that contains an array of AttributeAssignmentError
- # objects, each corresponding to the error while assigning to an attribute.
- class MultiparameterAssignmentErrors < ActiveRecordError
- attr_reader :errors
- def initialize(errors)
- @errors = errors
- end
- end
-
# Active Record objects don't specify their attributes directly, but rather infer them from the table definition with
# which they're linked. Adding, removing, and changing attributes and their type is done directly in the database. Any change
# is instantly reflected in the Active Record objects. The mapping that binds a given Active Record class to a certain
@@ -551,7 +389,7 @@ module ActiveRecord #:nodoc:
class << self # Class methods
def colorize_logging(*args)
ActiveSupport::Deprecation.warn "ActiveRecord::Base.colorize_logging and " <<
- "config.active_record.colorize_logging are deprecated. Please use " <<
+ "config.active_record.colorize_logging are deprecated. Please use " <<
"Rails::LogSubscriber.colorize_logging or config.colorize_logging instead", caller
end
alias :colorize_logging= :colorize_logging
@@ -2401,8 +2239,10 @@ module ActiveRecord #:nodoc:
include Aggregations, Transactions, Reflection, Serialization
+ NilClass.add_whiner(self) if NilClass.respond_to?(:add_whiner)
end
end
# TODO: Remove this and make it work with LAZY flag
require 'active_record/connection_adapters/abstract_adapter'
+ActiveRecord.run_base_hooks(ActiveRecord::Base) \ No newline at end of file
diff --git a/activerecord/lib/active_record/errors.rb b/activerecord/lib/active_record/errors.rb
new file mode 100644
index 0000000000..cf5ddca2ba
--- /dev/null
+++ b/activerecord/lib/active_record/errors.rb
@@ -0,0 +1,165 @@
+module ActiveRecord
+ # Generic Active Record exception class.
+ class ActiveRecordError < StandardError
+ end
+
+ # Raised when the single-table inheritance mechanism fails to locate the subclass
+ # (for example due to improper usage of column that +inheritance_column+ points to).
+ class SubclassNotFound < ActiveRecordError #:nodoc:
+ end
+
+ # Raised when an object assigned to an association has an incorrect type.
+ #
+ # class Ticket < ActiveRecord::Base
+ # has_many :patches
+ # end
+ #
+ # class Patch < ActiveRecord::Base
+ # belongs_to :ticket
+ # end
+ #
+ # # Comments are not patches, this assignment raises AssociationTypeMismatch.
+ # @ticket.patches << Comment.new(:content => "Please attach tests to your patch.")
+ class AssociationTypeMismatch < ActiveRecordError
+ end
+
+ # Raised when unserialized object's type mismatches one specified for serializable field.
+ class SerializationTypeMismatch < ActiveRecordError
+ end
+
+ # Raised when adapter not specified on connection (or configuration file <tt>config/database.yml</tt> misses adapter field).
+ class AdapterNotSpecified < ActiveRecordError
+ end
+
+ # Raised when Active Record cannot find database adapter specified in <tt>config/database.yml</tt> or programmatically.
+ class AdapterNotFound < ActiveRecordError
+ end
+
+ # Raised when connection to the database could not been established (for example when <tt>connection=</tt> is given a nil object).
+ class ConnectionNotEstablished < ActiveRecordError
+ end
+
+ # Raised when Active Record cannot find record by given id or set of ids.
+ class RecordNotFound < ActiveRecordError
+ end
+
+ # Raised by ActiveRecord::Base.save! and ActiveRecord::Base.create! methods when record cannot be
+ # saved because record is invalid.
+ class RecordNotSaved < ActiveRecordError
+ end
+
+ # Raised when SQL statement cannot be executed by the database (for example, it's often the case for MySQL when Ruby driver used is too old).
+ class StatementInvalid < ActiveRecordError
+ end
+
+ # Raised when SQL statement is invalid and the application gets a blank result.
+ class ThrowResult < ActiveRecordError
+ end
+
+ # Parent class for all specific exceptions which wrap database driver exceptions
+ # provides access to the original exception also.
+ class WrappedDatabaseException < StatementInvalid
+ attr_reader :original_exception
+
+ def initialize(message, original_exception)
+ super(message)
+ @original_exception = original_exception
+ end
+ end
+
+ # Raised when a record cannot be inserted because it would violate a uniqueness constraint.
+ class RecordNotUnique < WrappedDatabaseException
+ end
+
+ # Raised when a record cannot be inserted or updated because it references a non-existent record.
+ class InvalidForeignKey < WrappedDatabaseException
+ end
+
+ # Raised when number of bind variables in statement given to <tt>:condition</tt> key (for example, when using +find+ method)
+ # does not match number of expected variables.
+ #
+ # For example, in
+ #
+ # Location.find :all, :conditions => ["lat = ? AND lng = ?", 53.7362]
+ #
+ # two placeholders are given but only one variable to fill them.
+ class PreparedStatementInvalid < ActiveRecordError
+ end
+
+ # Raised on attempt to save stale record. Record is stale when it's being saved in another query after
+ # instantiation, for example, when two users edit the same wiki page and one starts editing and saves
+ # the page before the other.
+ #
+ # Read more about optimistic locking in ActiveRecord::Locking module RDoc.
+ class StaleObjectError < ActiveRecordError
+ end
+
+ # Raised when association is being configured improperly or
+ # user tries to use offset and limit together with has_many or has_and_belongs_to_many associations.
+ class ConfigurationError < ActiveRecordError
+ end
+
+ # Raised on attempt to update record that is instantiated as read only.
+ class ReadOnlyRecord < ActiveRecordError
+ end
+
+ # ActiveRecord::Transactions::ClassMethods.transaction uses this exception
+ # to distinguish a deliberate rollback from other exceptional situations.
+ # Normally, raising an exception will cause the +transaction+ method to rollback
+ # the database transaction *and* pass on the exception. But if you raise an
+ # ActiveRecord::Rollback exception, then the database transaction will be rolled back,
+ # without passing on the exception.
+ #
+ # For example, you could do this in your controller to rollback a transaction:
+ #
+ # class BooksController < ActionController::Base
+ # def create
+ # Book.transaction do
+ # book = Book.new(params[:book])
+ # book.save!
+ # if today_is_friday?
+ # # The system must fail on Friday so that our support department
+ # # won't be out of job. We silently rollback this transaction
+ # # without telling the user.
+ # raise ActiveRecord::Rollback, "Call tech support!"
+ # end
+ # end
+ # # ActiveRecord::Rollback is the only exception that won't be passed on
+ # # by ActiveRecord::Base.transaction, so this line will still be reached
+ # # even on Friday.
+ # redirect_to root_url
+ # end
+ # end
+ class Rollback < ActiveRecordError
+ end
+
+ # Raised when attribute has a name reserved by Active Record (when attribute has name of one of Active Record instance methods).
+ class DangerousAttributeError < ActiveRecordError
+ end
+
+ # Raised when unknown attributes are supplied via mass assignment.
+ class UnknownAttributeError < NoMethodError
+ end
+
+ # Raised when an error occurred while doing a mass assignment to an attribute through the
+ # <tt>attributes=</tt> method. The exception has an +attribute+ property that is the name of the
+ # offending attribute.
+ class AttributeAssignmentError < ActiveRecordError
+ attr_reader :exception, :attribute
+ def initialize(message, exception, attribute)
+ @exception = exception
+ @attribute = attribute
+ @message = message
+ end
+ end
+
+ # Raised when there are multiple errors while doing a mass assignment through the +attributes+
+ # method. The exception has an +errors+ property that contains an array of AttributeAssignmentError
+ # objects, each corresponding to the error while assigning to an attribute.
+ class MultiparameterAssignmentErrors < ActiveRecordError
+ attr_reader :errors
+ def initialize(errors)
+ @errors = errors
+ end
+ end
+end \ No newline at end of file
diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb
index b38bd9a644..60addd46c6 100644
--- a/activerecord/lib/active_record/railtie.rb
+++ b/activerecord/lib/active_record/railtie.rb
@@ -24,31 +24,39 @@ module ActiveRecord
log_subscriber ActiveRecord::Railties::LogSubscriber.new
initializer "active_record.initialize_timezone" do
- ActiveRecord::Base.time_zone_aware_attributes = true
- ActiveRecord::Base.default_timezone = :utc
+ ActiveRecord.base_hook do
+ self.time_zone_aware_attributes = true
+ self.default_timezone = :utc
+ end
end
initializer "active_record.logger" do
- ActiveRecord::Base.logger ||= ::Rails.logger
+ ActiveRecord.base_hook { self.logger ||= ::Rails.logger }
end
initializer "active_record.set_configs" do |app|
- app.config.active_record.each do |k,v|
- ActiveRecord::Base.send "#{k}=", v
+ ActiveRecord.base_hook do
+ app.config.active_record.each do |k,v|
+ send "#{k}=", v
+ end
end
end
# This sets the database configuration from Configuration#database_configuration
# and then establishes the connection.
initializer "active_record.initialize_database" do |app|
- ActiveRecord::Base.configurations = app.config.database_configuration
- ActiveRecord::Base.establish_connection
+ ActiveRecord.base_hook do
+ self.configurations = app.config.database_configuration
+ establish_connection
+ end
end
# Expose database runtime to controller for logging.
initializer "active_record.log_runtime" do |app|
require "active_record/railties/controller_runtime"
- ActionController::Base.send :include, ActiveRecord::Railties::ControllerRuntime
+ ActionController.base_hook do
+ include ActiveRecord::Railties::ControllerRuntime
+ end
end
# Setup database middleware after initializers have run
@@ -64,18 +72,22 @@ module ActiveRecord
end
initializer "active_record.load_observers" do
- ActiveRecord::Base.instantiate_observers
+ ActiveRecord.base_hook { instantiate_observers }
- ActionDispatch::Callbacks.to_prepare(:activerecord_instantiate_observers) do
- ActiveRecord::Base.instantiate_observers
+ ActiveRecord.base_hook do
+ ActionDispatch::Callbacks.to_prepare(:activerecord_instantiate_observers) do
+ ActiveRecord::Base.instantiate_observers
+ end
end
end
initializer "active_record.set_dispatch_hooks", :before => :set_clear_dependencies_hook do |app|
- unless app.config.cache_classes
- ActionDispatch::Callbacks.after do
- ActiveRecord::Base.reset_subclasses
- ActiveRecord::Base.clear_reloadable_connections!
+ ActiveRecord.base_hook do
+ unless app.config.cache_classes
+ ActionDispatch::Callbacks.after do
+ ActiveRecord::Base.reset_subclasses
+ ActiveRecord::Base.clear_reloadable_connections!
+ end
end
end
end
diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb
index f77dc801dc..e831ebf36c 100644
--- a/activerecord/test/cases/helper.rb
+++ b/activerecord/test/cases/helper.rb
@@ -9,6 +9,7 @@ require 'test/unit'
require 'stringio'
require 'active_record'
+require 'active_support/dependencies'
require 'connection'
begin
diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb
index ae31d191c0..e34e46b4cf 100644
--- a/activesupport/lib/active_support.rb
+++ b/activesupport/lib/active_support.rb
@@ -53,6 +53,7 @@ module ActiveSupport
autoload :Deprecation
autoload :Gzip
autoload :Inflector
+ autoload :JSON
autoload :Memoizable
autoload :MessageEncryptor
autoload :MessageVerifier
@@ -70,3 +71,5 @@ module ActiveSupport
autoload :SafeBuffer, "active_support/core_ext/string/output_safety"
autoload :TestCase
end
+
+autoload :I18n, "active_support/i18n"
diff --git a/activesupport/lib/active_support/all.rb b/activesupport/lib/active_support/all.rb
index 64600575d9..f537818300 100644
--- a/activesupport/lib/active_support/all.rb
+++ b/activesupport/lib/active_support/all.rb
@@ -1,4 +1,3 @@
require 'active_support'
-require 'active_support/i18n'
require 'active_support/time'
require 'active_support/core_ext'
diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb
index 814567a5a6..2119322bfe 100644
--- a/activesupport/lib/active_support/core_ext/array/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/array/conversions.rb
@@ -1,7 +1,6 @@
require 'active_support/core_ext/hash/keys'
require 'active_support/core_ext/hash/reverse_merge'
require 'active_support/inflector'
-require 'active_support/i18n'
class Array
# Converts the array to a comma-separated sentence where the last element is joined by the connector word. Options:
diff --git a/activesupport/lib/active_support/core_ext/string/interpolation.rb b/activesupport/lib/active_support/core_ext/string/interpolation.rb
index 06d3505c60..932117cc10 100644
--- a/activesupport/lib/active_support/core_ext/string/interpolation.rb
+++ b/activesupport/lib/active_support/core_ext/string/interpolation.rb
@@ -1,91 +1 @@
-=begin
- heavily based on Masao Mutoh's gettext String interpolation extension
- http://github.com/mutoh/gettext/blob/f6566738b981fe0952548c421042ad1e0cdfb31e/lib/gettext/core_ext/string.rb
- Copyright (C) 2005-2010 Masao Mutoh
- You may redistribute it and/or modify it under the same license terms as Ruby.
-=end
-
-if RUBY_VERSION < '1.9' && !"".respond_to?(:interpolate_without_ruby_19_syntax)
-
- # KeyError is raised by String#% when the string contains a named placeholder
- # that is not contained in the given arguments hash. Ruby 1.9 includes and
- # raises this exception natively. We define it to mimic Ruby 1.9's behaviour
- # in Ruby 1.8.x
-
- class KeyError < IndexError
- def initialize(message = nil)
- super(message || "key not found")
- end
- end unless defined?(KeyError)
-
- # Extension for String class. This feature is included in Ruby 1.9 or later but not occur TypeError.
- #
- # String#% method which accept "named argument". The translator can know
- # the meaning of the msgids using "named argument" instead of %s/%d style.
-
- class String
- alias :interpolate_without_ruby_19_syntax :% # :nodoc:
-
- INTERPOLATION_PATTERN = Regexp.union(
- /%%/,
- /%\{(\w+)\}/, # matches placeholders like "%{foo}"
- /%<(\w+)>(.*?\d*\.?\d*[bBdiouxXeEfgGcps])/ # matches placeholders like "%<foo>.d"
- )
-
- # % uses self (i.e. the String) as a format specification and returns the
- # result of applying it to the given arguments. In other words it interpolates
- # the given arguments to the string according to the formats the string
- # defines.
- #
- # There are three ways to use it:
- #
- # * Using a single argument or Array of arguments.
- #
- # This is the default behaviour of the String class. See Kernel#sprintf for
- # more details about the format string.
- #
- # Example:
- #
- # "%d %s" % [1, "message"]
- # # => "1 message"
- #
- # * Using a Hash as an argument and unformatted, named placeholders.
- #
- # When you pass a Hash as an argument and specify placeholders with %{foo}
- # it will interpret the hash values as named arguments.
- #
- # Example:
- #
- # "%{firstname}, %{lastname}" % {:firstname => "Masao", :lastname => "Mutoh"}
- # # => "Masao Mutoh"
- #
- # * Using a Hash as an argument and formatted, named placeholders.
- #
- # When you pass a Hash as an argument and specify placeholders with %<foo>d
- # it will interpret the hash values as named arguments and format the value
- # according to the formatting instruction appended to the closing >.
- #
- # Example:
- #
- # "%<integer>d, %<float>.1f" % { :integer => 10, :float => 43.4 }
- # # => "10, 43.3"
- def %(args)
- if args.kind_of?(Hash)
- dup.gsub(INTERPOLATION_PATTERN) do |match|
- if match == '%%'
- '%'
- else
- key = ($1 || $2).to_sym
- raise KeyError unless args.has_key?(key)
- $3 ? sprintf("%#{$3}", args[key]) : args[key]
- end
- end
- elsif self =~ INTERPOLATION_PATTERN
- raise ArgumentError.new('one hash required')
- else
- result = gsub(/%([{<])/, '%%\1')
- result.send :'interpolate_without_ruby_19_syntax', args
- end
- end
- end
-end
+require 'i18n/core_ext/string/interpolate'
diff --git a/activesupport/lib/active_support/dependencies/autoload.rb b/activesupport/lib/active_support/dependencies/autoload.rb
index 44edb89ad5..f669f4a77e 100644
--- a/activesupport/lib/active_support/dependencies/autoload.rb
+++ b/activesupport/lib/active_support/dependencies/autoload.rb
@@ -1,7 +1,12 @@
require "active_support/inflector/methods"
+require "active_support/lazy_load_hooks"
module ActiveSupport
module Autoload
+ def self.extended(base)
+ base.extend(LazyLoadHooks)
+ end
+
@@autoloads = {}
@@under_path = nil
@@at_path = nil
diff --git a/activesupport/lib/active_support/i18n.rb b/activesupport/lib/active_support/i18n.rb
index 854c60eec1..034d7d8ddc 100644
--- a/activesupport/lib/active_support/i18n.rb
+++ b/activesupport/lib/active_support/i18n.rb
@@ -1,2 +1,3 @@
require 'i18n'
-I18n.load_path << "#{File.dirname(__FILE__)}/locale/en.yml" \ No newline at end of file
+I18n.load_path << "#{File.dirname(__FILE__)}/locale/en.yml"
+ActiveSupport.run_base_hooks(:i18n) \ No newline at end of file
diff --git a/activesupport/lib/active_support/lazy_load_hooks.rb b/activesupport/lib/active_support/lazy_load_hooks.rb
new file mode 100644
index 0000000000..36acfda524
--- /dev/null
+++ b/activesupport/lib/active_support/lazy_load_hooks.rb
@@ -0,0 +1,25 @@
+module ActiveSupport
+ module LazyLoadHooks
+ def _setup_base_hooks
+ @base_hooks ||= Hash.new {|h,k| h[k] = [] }
+ @base ||= {}
+ end
+
+ def base_hook(name = nil, &block)
+ _setup_base_hooks
+
+ if base = @base[name]
+ base.instance_eval(&block)
+ else
+ @base_hooks[name] << block
+ end
+ end
+
+ def run_base_hooks(base, name = nil)
+ _setup_base_hooks
+
+ @base_hooks[name].each { |hook| base.instance_eval(&hook) } if @base_hooks
+ @base[name] = base
+ end
+ end
+end \ No newline at end of file
diff --git a/activesupport/lib/active_support/railtie.rb b/activesupport/lib/active_support/railtie.rb
index 58d11585ba..d2c13e030d 100644
--- a/activesupport/lib/active_support/railtie.rb
+++ b/activesupport/lib/active_support/railtie.rb
@@ -37,10 +37,12 @@ module I18n
config.i18n.load_path = []
initializer "i18n.initialize" do
- require 'active_support/i18n'
-
- ActionDispatch::Callbacks.to_prepare do
+ ActiveSupport.base_hook(:i18n) do
I18n.reload!
+
+ ActionDispatch::Callbacks.to_prepare do
+ I18n.reload!
+ end
end
end
diff --git a/activesupport/lib/active_support/whiny_nil.rb b/activesupport/lib/active_support/whiny_nil.rb
index 0b68e936f6..91ddef2619 100644
--- a/activesupport/lib/active_support/whiny_nil.rb
+++ b/activesupport/lib/active_support/whiny_nil.rb
@@ -25,17 +25,16 @@
# By default it is on in development and test modes, and it is off in production
# mode.
class NilClass
- WHINERS = [::Array]
- WHINERS << ::ActiveRecord::Base if defined? ::ActiveRecord::Base
-
METHOD_CLASS_MAP = Hash.new
- WHINERS.each do |klass|
+ def self.add_whiner(klass)
methods = klass.public_instance_methods - public_instance_methods
class_name = klass.name
methods.each { |method| METHOD_CLASS_MAP[method.to_sym] = class_name }
end
+ add_whiner ::Array
+
# Raises a RuntimeError when you attempt to call +id+ on +nil+.
def id
raise RuntimeError, "Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id", caller
diff --git a/activesupport/test/whiny_nil_test.rb b/activesupport/test/whiny_nil_test.rb
index 1e4f8d854a..4b9f06dead 100644
--- a/activesupport/test/whiny_nil_test.rb
+++ b/activesupport/test/whiny_nil_test.rb
@@ -9,6 +9,8 @@ end
require 'abstract_unit'
require 'active_support/whiny_nil'
+NilClass.add_whiner ::ActiveRecord::Base
+
class WhinyNilTest < Test::Unit::TestCase
def test_unchanged
nil.method_thats_not_in_whiners
diff --git a/railties/lib/rails/application/routes_reloader.rb b/railties/lib/rails/application/routes_reloader.rb
index fde6211c5d..a5154f4bba 100644
--- a/railties/lib/rails/application/routes_reloader.rb
+++ b/railties/lib/rails/application/routes_reloader.rb
@@ -27,7 +27,7 @@ module Rails
routes.clear!
paths.each { |path| load(path) }
- routes.finalize!
+ ActionController.base_hook { routes.finalize! }
nil
ensure
diff --git a/railties/lib/rails/console/helpers.rb b/railties/lib/rails/console/helpers.rb
index 039db667c4..212fc6125a 100644
--- a/railties/lib/rails/console/helpers.rb
+++ b/railties/lib/rails/console/helpers.rb
@@ -2,4 +2,6 @@ def helper
@helper ||= ApplicationController.helpers
end
-@controller = ApplicationController.new
+def controller
+ @controller ||= ApplicationController.new
+end
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 8f5040ea13..85b4ff8470 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -97,8 +97,8 @@ module Rails
initializer :add_view_paths do
views = paths.app.views.to_a
- ActionController::Base.prepend_view_path(views) if defined?(ActionController::Base)
- ActionMailer::Base.prepend_view_path(views) if defined?(ActionMailer::Base)
+ ActionController.base_hook { prepend_view_path(views) } if defined?(ActionController)
+ ActionMailer.base_hook { prepend_view_path(views) } if defined?(ActionMailer)
end
initializer :add_metals do |app|