mirror of
https://github.com/github/rails.git
synced 2026-04-26 03:00:59 -04:00
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
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -58,6 +58,8 @@ module ActionController
|
||||
filter
|
||||
end
|
||||
|
||||
ActionController.run_base_hooks(self)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
require 'active_support/json'
|
||||
require 'action_dispatch/http/request'
|
||||
|
||||
module ActionDispatch
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
require 'active_support/core_ext/hash/keys'
|
||||
require 'rack/request'
|
||||
|
||||
module ActionDispatch
|
||||
module Session
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
require 'action_controller/test_case'
|
||||
require 'action_view'
|
||||
|
||||
module ActionView
|
||||
class Base
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
@@ -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)
|
||||
165
activerecord/lib/active_record/errors.rb
Normal file
165
activerecord/lib/active_record/errors.rb
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -9,6 +9,7 @@ require 'test/unit'
|
||||
require 'stringio'
|
||||
|
||||
require 'active_record'
|
||||
require 'active_support/dependencies'
|
||||
require 'connection'
|
||||
|
||||
begin
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
require 'active_support'
|
||||
require 'active_support/i18n'
|
||||
require 'active_support/time'
|
||||
require 'active_support/core_ext'
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
require 'i18n'
|
||||
I18n.load_path << "#{File.dirname(__FILE__)}/locale/en.yml"
|
||||
I18n.load_path << "#{File.dirname(__FILE__)}/locale/en.yml"
|
||||
ActiveSupport.run_base_hooks(:i18n)
|
||||
25
activesupport/lib/active_support/lazy_load_hooks.rb
Normal file
25
activesupport/lib/active_support/lazy_load_hooks.rb
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -27,7 +27,7 @@ module Rails
|
||||
|
||||
routes.clear!
|
||||
paths.each { |path| load(path) }
|
||||
routes.finalize!
|
||||
ActionController.base_hook { routes.finalize! }
|
||||
|
||||
nil
|
||||
ensure
|
||||
|
||||
@@ -2,4 +2,6 @@ def helper
|
||||
@helper ||= ApplicationController.helpers
|
||||
end
|
||||
|
||||
@controller = ApplicationController.new
|
||||
def controller
|
||||
@controller ||= ApplicationController.new
|
||||
end
|
||||
|
||||
@@ -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|
|
||||
|
||||
Reference in New Issue
Block a user