diff options
42 files changed, 374 insertions, 361 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 bc708cca56..cd0c5bea53 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -289,6 +289,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/actionpack.gemspec b/actionpack/actionpack.gemspec index 790efc4ec5..ed5b7e1e93 100644 --- a/actionpack/actionpack.gemspec +++ b/actionpack/actionpack.gemspec @@ -23,6 +23,6 @@ Gem::Specification.new do |s| s.add_dependency('activemodel', version) s.add_dependency('rack', '~> 1.1.0') s.add_dependency('rack-test', '~> 0.5.0') - s.add_dependency('rack-mount', '~> 0.5.1') + s.add_dependency('rack-mount', '~> 0.6.0') s.add_dependency('erubis', '~> 2.6.5') 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/deprecated/base.rb b/actionpack/lib/action_controller/deprecated/base.rb index 34f8f4a822..1d05b3fbd6 100644 --- a/actionpack/lib/action_controller/deprecated/base.rb +++ b/actionpack/lib/action_controller/deprecated/base.rb @@ -57,7 +57,7 @@ module ActionController def ip_spoofing_check=(value) ActiveSupport::Deprecation.warn "ActionController::Base.ip_spoofing_check= is deprecated. " << "Please configure it on your application with config.action_dispatch.ip_spoofing_check=", caller - Rails.application.config.action_disaptch.ip_spoofing_check = value + Rails.application.config.action_dispatch.ip_spoofing_check = value end def ip_spoofing_check 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..7a33259054 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 @@ -450,7 +452,10 @@ module ActionDispatch scope(:path => resource.name.to_s, :controller => resource.controller) do with_scope_level(:resource, resource) do - yield if block_given? + + scope(:name_prefix => resource.name.to_s) do + yield if block_given? + end get :show if resource.actions.include?(:show) post :create if resource.actions.include?(:create) diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb index c37cea824a..7e9ac8720c 100644 --- a/actionpack/lib/action_view.rb +++ b/actionpack/lib/action_view.rb @@ -42,12 +42,13 @@ module ActionView autoload :Rendering end - autoload :LookupContext, 'action_view/lookup_context' - autoload :MissingTemplate, 'action_view/base' - autoload :Resolver, 'action_view/template/resolver' - autoload :PathResolver, 'action_view/template/resolver' - autoload :PathSet, 'action_view/paths' - autoload :FileSystemResolverWithFallback, 'action_view/template/resolver' + autoload :Base + autoload :LookupContext + autoload :MissingTemplate, 'action_view/base' + autoload :Resolver, 'action_view/template/resolver' + autoload :PathResolver, 'action_view/template/resolver' + autoload :FileSystemResolver, 'action_view/template/resolver' + autoload :PathSet, 'action_view/paths' autoload :TemplateError, 'action_view/template/error' autoload :TemplateHandler, 'action_view/template' @@ -58,6 +59,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 d2b77b2560..38413560f3 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -176,6 +176,8 @@ module ActionView #:nodoc: include Helpers, Rendering, Partials, Layouts, ::ERB::Util, Context extend ActiveSupport::Memoizable + ActionView.run_base_hooks(self) + # Specify whether RJS responses should be wrapped in a try/catch block # that alert()s the caught exception (and then re-raises it). cattr_accessor :debug_rjs 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/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 37c2f1421b..b46276c453 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -24,6 +24,8 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest resource :session do get :create + + resource :info end match 'account/logout' => redirect("/logout"), :as => :logout_redirect @@ -234,6 +236,14 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest end end + def test_session_info_nested_singleton_resource + with_test_routes do + get '/session/info' + assert_equal 'infos#show', @response.body + assert_equal '/session/info', session_info_path + end + end + def test_redirect_modulo with_test_routes do get '/account/modulo/name' 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/generators/rails/app/templates/Gemfile b/railties/lib/generators/rails/app/templates/Gemfile index f4bce8646d..0dd10f3f2d 100644 --- a/railties/lib/generators/rails/app/templates/Gemfile +++ b/railties/lib/generators/rails/app/templates/Gemfile @@ -1,4 +1,4 @@ -source 'http://gemcutter.org' +source 'http://rubygems.org' <%- if options.dev? -%> gem 'rails', :path => '<%= Rails::Generators::RAILS_DEV_PATH %>' @@ -15,15 +15,15 @@ gem 'rails', '<%= Rails::VERSION::STRING %>' gem '<%= gem_for_database %>'<% if require_for_database %>, :require => '<%= require_for_database %>'<% end %> <% end -%> -# Use mongrel as the web server -# gem 'mongrel' +# Use unicorn as the web server +# gem 'unicorn' # Deploy with Capistrano # gem 'capistrano' # Bundle the extra gems: # gem 'bj' -# gem 'hpricot', '0.6' +# gem 'nokogiri', '1.4.1' # gem 'sqlite3-ruby', :require => 'sqlite3' # gem 'aws-s3', :require => 'aws/s3' diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index d9089b18f0..f43e8847ac 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -15,7 +15,10 @@ module Rails class << self private :new - alias :configure :class_eval + + def configure(&block) + class_eval(&block) + end def instance if self == Rails::Application diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index a00f9c43ae..d3a0ecb243 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -21,6 +21,10 @@ module Rails @consider_all_requests_local = true end + def middleware + @@default_middleware_stack ||= default_middleware + end + def paths @paths ||= begin paths = super 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| diff --git a/railties/lib/rails/railtie/configuration.rb b/railties/lib/rails/railtie/configuration.rb index 6a8c4ca09f..828ccec3d0 100644 --- a/railties/lib/rails/railtie/configuration.rb +++ b/railties/lib/rails/railtie/configuration.rb @@ -10,10 +10,6 @@ module Rails @session_options = {} end - def middleware - @@default_middleware_stack ||= default_middleware - end - # Holds generators configuration: # # config.generators do |g| diff --git a/railties/lib/rails/tasks/documentation.rake b/railties/lib/rails/tasks/documentation.rake index 1f4067d29e..abf9b33ae5 100644 --- a/railties/lib/rails/tasks/documentation.rake +++ b/railties/lib/rails/tasks/documentation.rake @@ -11,44 +11,54 @@ namespace :doc do rdoc.rdoc_files.include('lib/**/*.rb') } - desc 'Generate documentation for the Rails framework. Specify path with PATH="/path/to/rails"' - Rake::RDocTask.new("rails") { |rdoc| - path = ENV['RAILS_PATH'] || 'vendor/gems/gems' - version = "-#{Rails::VERSION::STRING}" unless ENV['RAILS_PATH'] - rdoc.rdoc_dir = 'doc/api' - rdoc.template = "#{ENV['template']}.rb" if ENV['template'] - rdoc.title = "Rails Framework Documentation" - rdoc.options << '--line-numbers' << '--inline-source' - rdoc.rdoc_files.include('README') - - %w(README CHANGELOG lib/action_mailer/base.rb).each do |file| - rdoc.rdoc_files.include("#{path}/actionmailer#{version}/#{file}") + desc 'Generate documentation for the Rails framework. Specify path with RAILS_PATH="/path/to/rails"' + path = ENV['RAILS_PATH'] + unless path && File.directory?(path) + task :rails do + if path + $stderr.puts "Skipping doc:rails, missing Rails directory at #{path}" + else + $stderr.puts "Skipping doc:rails, RAILS_PATH environment variable is not set" + end end + else + Rake::RDocTask.new("rails") { |rdoc| + version = "-#{Rails::VERSION::STRING}" unless ENV['RAILS_PATH'] + rdoc.rdoc_dir = 'doc/api' + rdoc.template = "#{ENV['template']}.rb" if ENV['template'] + rdoc.title = "Rails Framework Documentation" + rdoc.options << '--line-numbers' << '--inline-source' + rdoc.rdoc_files.include('README') + + %w(README CHANGELOG lib/action_mailer/base.rb).each do |file| + rdoc.rdoc_files.include("#{path}/actionmailer#{version}/#{file}") + end - %w(README CHANGELOG lib/action_controller/**/*.rb lib/action_view/**/*.rb).each do |file| - rdoc.rdoc_files.include("#{path}/actionpack#{version}/#{file}") - end + %w(README CHANGELOG lib/action_controller/**/*.rb lib/action_view/**/*.rb).each do |file| + rdoc.rdoc_files.include("#{path}/actionpack#{version}/#{file}") + end - %w(README CHANGELOG lib/active_model/**/*.rb).each do |file| - rdoc.rdoc_files.include("#{path}/activemodel#{version}/#{file}") - end + %w(README CHANGELOG lib/active_model/**/*.rb).each do |file| + rdoc.rdoc_files.include("#{path}/activemodel#{version}/#{file}") + end - %w(README CHANGELOG lib/active_record/**/*.rb).each do |file| - rdoc.rdoc_files.include("#{path}/activerecord#{version}/#{file}") - end + %w(README CHANGELOG lib/active_record/**/*.rb).each do |file| + rdoc.rdoc_files.include("#{path}/activerecord#{version}/#{file}") + end - %w(README CHANGELOG lib/active_resource.rb lib/active_resource/*).each do |file| - rdoc.rdoc_files.include("#{path}/activeresource#{version}/#{file}") - end + %w(README CHANGELOG lib/active_resource.rb lib/active_resource/*).each do |file| + rdoc.rdoc_files.include("#{path}/activeresource#{version}/#{file}") + end - %w(README CHANGELOG lib/active_support/**/*.rb).each do |file| - rdoc.rdoc_files.include("#{path}/activesupport#{version}/#{file}") - end + %w(README CHANGELOG lib/active_support/**/*.rb).each do |file| + rdoc.rdoc_files.include("#{path}/activesupport#{version}/#{file}") + end - %w(README CHANGELOG MIT-LICENSE lib/{*.rb,commands/*.rb,generators/*.rb}).each do |file| - rdoc.rdoc_files.include("#{path}/railties#{version}/#{file}") - end - } + %w(README CHANGELOG MIT-LICENSE lib/{*.rb,commands/*.rb,generators/*.rb}).each do |file| + rdoc.rdoc_files.include("#{path}/railties#{version}/#{file}") + end + } + end plugins = FileList['vendor/plugins/**'].collect { |plugin| File.basename(plugin) } |