diff options
30 files changed, 179 insertions, 90 deletions
diff --git a/actionpack/lib/action_controller/metal/exceptions.rb b/actionpack/lib/action_controller/metal/exceptions.rb index 5260dc0336..5c0ada37be 100644 --- a/actionpack/lib/action_controller/metal/exceptions.rb +++ b/actionpack/lib/action_controller/metal/exceptions.rb @@ -3,12 +3,19 @@ module ActionController end class BadRequest < ActionControllerError #:nodoc: - attr_reader :original_exception - def initialize(msg = nil, e = nil) + if e + ActiveSupport::Deprecation.warn("Passing #original_exception is deprecated and has no effect. " \ + "Exceptions will automatically capture the original exception.", caller) + end + super(msg) - @original_exception = e - set_backtrace e.backtrace if e + set_backtrace $!.backtrace if $! + end + + def original_exception + ActiveSupport::Deprecation.warn("#original_exception is deprecated. Use #cause instead.", caller) + cause end end diff --git a/actionpack/lib/action_controller/metal/rescue.rb b/actionpack/lib/action_controller/metal/rescue.rb index 68cc9a9c9b..81b9a7b9ed 100644 --- a/actionpack/lib/action_controller/metal/rescue.rb +++ b/actionpack/lib/action_controller/metal/rescue.rb @@ -7,10 +7,8 @@ module ActionController #:nodoc: include ActiveSupport::Rescuable def rescue_with_handler(exception) - if (exception.respond_to?(:original_exception) && - (orig_exception = exception.original_exception) && - handler_for_rescue(orig_exception)) - exception = orig_exception + if exception.cause && handler_for_rescue(exception.cause) + exception = exception.cause end super(exception) end diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb index 248ecfd676..c9df787351 100644 --- a/actionpack/lib/action_dispatch/http/parameters.rb +++ b/actionpack/lib/action_dispatch/http/parameters.rb @@ -55,11 +55,11 @@ module ActionDispatch begin strategy.call(raw_post) - rescue => e # JSON or Ruby code block errors + rescue # JSON or Ruby code block errors my_logger = logger || ActiveSupport::Logger.new($stderr) my_logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{raw_post}" - raise ParamsParser::ParseError.new(e.message, e) + raise ParamsParser::ParseError end end diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index 35e3ac304f..ea61ad0c02 100644 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -344,7 +344,7 @@ module ActionDispatch set_header k, Request::Utils.normalize_encode_params(rack_query_params) end rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e - raise ActionController::BadRequest.new("Invalid query parameters: #{e.message}", e) + raise ActionController::BadRequest.new("Invalid query parameters: #{e.message}") end alias :query_parameters :GET @@ -360,7 +360,7 @@ module ActionDispatch self.request_parameters = Request::Utils.normalize_encode_params(super || {}) raise rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e - raise ActionController::BadRequest.new("Invalid request parameters: #{e.message}", e) + raise ActionController::BadRequest.new("Invalid request parameters: #{e.message}") end alias :request_parameters :POST diff --git a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb index 5fd984cd07..3b61824cc9 100644 --- a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb +++ b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb @@ -37,7 +37,7 @@ module ActionDispatch @backtrace_cleaner = backtrace_cleaner @exception = original_exception(exception) - expand_backtrace if exception.is_a?(SyntaxError) || exception.try(:original_exception).try(:is_a?, SyntaxError) + expand_backtrace if exception.is_a?(SyntaxError) || exception.cause.is_a?(SyntaxError) end def rescue_template @@ -106,17 +106,13 @@ module ActionDispatch end def original_exception(exception) - if registered_original_exception?(exception) - exception.original_exception + if @@rescue_responses.has_key?(exception.cause.class.name) + exception.cause else exception end end - def registered_original_exception?(exception) - exception.respond_to?(:original_exception) && @@rescue_responses.has_key?(exception.original_exception.class.name) - end - def clean_backtrace(*args) if backtrace_cleaner backtrace_cleaner.clean(backtrace, *args) diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb index 18af0a583a..c2a4f46e67 100644 --- a/actionpack/lib/action_dispatch/middleware/params_parser.rb +++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb @@ -10,11 +10,25 @@ module ActionDispatch # Raised when raw data from the request cannot be parsed by the parser # defined for request's content mime type. class ParseError < StandardError - attr_reader :original_exception - def initialize(message, original_exception) - super(message) - @original_exception = original_exception + def initialize(message = nil, original_exception = nil) + if message + ActiveSupport::Deprecation.warn("Passing #message is deprecated and has no effect. " \ + "#{self.class} will automatically capture the message " \ + "of the original exception.", caller) + end + + if original_exception + ActiveSupport::Deprecation.warn("Passing #original_exception is deprecated and has no effect. " \ + "Exceptions will automatically capture the original exception.", caller) + end + + super($!.message) + end + + def original_exception + ActiveSupport::Deprecation.warn("#original_exception is deprecated. Use #cause instead.", caller) + cause end end diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb index 9e50fea3fc..5fb5953811 100644 --- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb @@ -7,14 +7,22 @@ require 'action_dispatch/request/session' module ActionDispatch module Session class SessionRestoreError < StandardError #:nodoc: - attr_reader :original_exception - def initialize(const_error) - @original_exception = const_error + def initialize(const_error = nil) + if const_error + ActiveSupport::Deprecation.warn("Passing #original_exception is deprecated and has no effect. " \ + "Exceptions will automatically capture the original exception.", caller) + end super("Session contains objects whose class definition isn't available.\n" + "Remember to require the classes for all objects kept in the session.\n" + - "(Original exception: #{const_error.message} [#{const_error.class}])\n") + "(Original exception: #{$!.message} [#{$!.class}])\n") + set_backtrace $!.backtrace + end + + def original_exception + ActiveSupport::Deprecation.warn("#original_exception is deprecated. Use #cause instead.", caller) + cause end end @@ -59,8 +67,8 @@ module ActionDispatch begin # Note that the regexp does not allow $1 to end with a ':' $1.constantize - rescue LoadError, NameError => e - raise ActionDispatch::Session::SessionRestoreError, e, e.backtrace + rescue LoadError, NameError + raise ActionDispatch::Session::SessionRestoreError end retry else diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb index c1e8b6cae3..5060da9369 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb @@ -1,6 +1,6 @@ <header> <h1> - <%= @exception.original_exception.class.to_s %> in + <%= @exception.cause.class.to_s %> in <%= @request.parameters["controller"].camelize if @request.parameters["controller"] %>#<%= @request.parameters["action"] %> </h1> </header> diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb index 77bcd26726..78d52acd96 100644 --- a/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb @@ -1,4 +1,4 @@ -<%= @exception.original_exception.class.to_s %> in <%= @request.parameters["controller"].camelize if @request.parameters["controller"] %>#<%= @request.parameters["action"] %> +<%= @exception.cause.class.to_s %> in <%= @request.parameters["controller"].camelize if @request.parameters["controller"] %>#<%= @request.parameters["action"] %> Showing <%= @exception.file_name %> where line #<%= @exception.line_number %> raised: <%= @exception.message %> diff --git a/actionpack/test/controller/rescue_test.rb b/actionpack/test/controller/rescue_test.rb index f53f061e10..f42bef883f 100644 --- a/actionpack/test/controller/rescue_test.rb +++ b/actionpack/test/controller/rescue_test.rb @@ -132,11 +132,19 @@ class RescueController < ActionController::Base end def io_error_in_view - raise ActionView::TemplateError.new(nil, IOError.new('this is io error')) + begin + raise IOError.new('this is io error') + rescue + raise ActionView::TemplateError.new(nil) + end end def zero_division_error_in_view - raise ActionView::TemplateError.new(nil, ZeroDivisionError.new('this is zero division error')) + begin + raise ZeroDivisionError.new('this is zero division error') + rescue + raise ActionView::TemplateError.new(nil) + end end protected diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb index 93258fbceb..89c3e75a50 100644 --- a/actionpack/test/dispatch/debug_exceptions_test.rb +++ b/actionpack/test/dispatch/debug_exceptions_test.rb @@ -42,7 +42,11 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest when "/unprocessable_entity" raise ActionController::InvalidAuthenticityToken when "/not_found_original_exception" - raise ActionView::Template::Error.new('template', AbstractController::ActionNotFound.new) + begin + raise AbstractController::ActionNotFound.new + rescue + raise ActionView::Template::Error.new('template') + end when "/missing_template" raise ActionView::MissingTemplate.new(%w(foo), 'foo/index', %w(foo), false, 'mailer') when "/bad_request" @@ -56,12 +60,12 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest when "/syntax_error_into_view" begin eval 'broke_syntax =' - rescue Exception => e + rescue Exception template = ActionView::Template.new(File.read(__FILE__), __FILE__, ActionView::Template::Handlers::Raw.new, {}) - raise ActionView::Template::Error.new(template, e) + raise ActionView::Template::Error.new(template) end when "/framework_raises" method_that_raises diff --git a/actionpack/test/dispatch/request/json_params_parsing_test.rb b/actionpack/test/dispatch/request/json_params_parsing_test.rb index 28ebaed663..a3992ad008 100644 --- a/actionpack/test/dispatch/request/json_params_parsing_test.rb +++ b/actionpack/test/dispatch/request/json_params_parsing_test.rb @@ -76,8 +76,8 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest $stderr = StringIO.new # suppress the log json = "[\"person]\": {\"name\": \"David\"}}" exception = assert_raise(ActionDispatch::ParamsParser::ParseError) { post "/parse", json, {'CONTENT_TYPE' => 'application/json', 'action_dispatch.show_exceptions' => false} } - assert_equal JSON::ParserError, exception.original_exception.class - assert_equal exception.original_exception.message, exception.message + assert_equal JSON::ParserError, exception.cause.class + assert_equal exception.cause.message, exception.message ensure $stderr = STDERR end diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb index e9896a71f4..22240699d9 100644 --- a/actionpack/test/dispatch/request_test.rb +++ b/actionpack/test/dispatch/request_test.rb @@ -1012,8 +1012,8 @@ class RequestParameters < BaseRequestTest request.parameters end - assert e.original_exception - assert_equal e.original_exception.backtrace, e.backtrace + assert_not_nil e.cause + assert_equal e.cause.backtrace, e.backtrace end end diff --git a/actionpack/test/dispatch/show_exceptions_test.rb b/actionpack/test/dispatch/show_exceptions_test.rb index 15dd702161..ffdf775836 100644 --- a/actionpack/test/dispatch/show_exceptions_test.rb +++ b/actionpack/test/dispatch/show_exceptions_test.rb @@ -9,13 +9,21 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest when "/not_found" raise AbstractController::ActionNotFound when "/bad_params" - raise ActionDispatch::ParamsParser::ParseError.new("", StandardError.new) + begin + raise StandardError.new + rescue + raise ActionDispatch::ParamsParser::ParseError + end when "/method_not_allowed" raise ActionController::MethodNotAllowed, 'PUT' when "/unknown_http_method" raise ActionController::UnknownHttpMethod when "/not_found_original_exception" - raise ActionView::Template::Error.new('template', AbstractController::ActionNotFound.new) + begin + raise AbstractController::ActionNotFound.new + rescue + raise ActionView::Template::Error.new('template') + end else raise "puke!" end diff --git a/actionview/lib/action_view/template.rb b/actionview/lib/action_view/template.rb index 0ed208f27e..15fc2b71a3 100644 --- a/actionview/lib/action_view/template.rb +++ b/actionview/lib/action_view/template.rb @@ -325,7 +325,7 @@ module ActionView template = refresh(view) template.encode! end - raise Template::Error.new(template, e) + raise Template::Error.new(template) end end diff --git a/actionview/lib/action_view/template/error.rb b/actionview/lib/action_view/template/error.rb index 390bce98a2..b03b197cb5 100644 --- a/actionview/lib/action_view/template/error.rb +++ b/actionview/lib/action_view/template/error.rb @@ -59,13 +59,20 @@ module ActionView class Error < ActionViewError #:nodoc: SOURCE_CODE_RADIUS = 3 - attr_reader :original_exception + def initialize(template, original_exception = nil) + if original_exception + ActiveSupport::Deprecation.warn("Passing #original_exception is deprecated and has no effect. " \ + "Exceptions will automatically capture the original exception.", caller) + end + + super($!.message) + set_backtrace($!.backtrace) + @template, @sub_templates = template, nil + end - def initialize(template, original_exception) - super(original_exception.message) - @template, @original_exception = template, original_exception - @sub_templates = nil - set_backtrace(original_exception.backtrace) + def original_exception + ActiveSupport::Deprecation.warn("#original_exception is deprecated. Use #cause instead.", caller) + cause end def file_name diff --git a/actionview/test/template/render_test.rb b/actionview/test/template/render_test.rb index 00fc28a522..51bc59edae 100644 --- a/actionview/test/template/render_test.rb +++ b/actionview/test/template/render_test.rb @@ -352,8 +352,8 @@ module RenderTestCases exception = assert_raises ActionView::Template::Error do @controller_view.render("partial_name_local_variable") end - assert_instance_of NameError, exception.original_exception - assert_equal :partial_name_local_variable, exception.original_exception.name + assert_instance_of NameError, exception.cause + assert_equal :partial_name_local_variable, exception.cause.name end # TODO: The reason for this test is unclear, improve documentation @@ -590,14 +590,14 @@ class LazyViewRenderTest < ActiveSupport::TestCase def test_render_utf8_template_with_incompatible_external_encoding with_external_encoding Encoding::SHIFT_JIS do e = assert_raises(ActionView::Template::Error) { @view.render(:file => "test/utf8", :formats => [:html], :layouts => "layouts/yield") } - assert_match 'Your template was not saved as valid Shift_JIS', e.original_exception.message + assert_match 'Your template was not saved as valid Shift_JIS', e.cause.message end end def test_render_utf8_template_with_partial_with_incompatible_encoding with_external_encoding Encoding::SHIFT_JIS do e = assert_raises(ActionView::Template::Error) { @view.render(:file => "test/utf8_magic_with_bare_partial", :formats => [:html], :layouts => "layouts/yield") } - assert_match 'Your template was not saved as valid Shift_JIS', e.original_exception.message + assert_match 'Your template was not saved as valid Shift_JIS', e.cause.message end end diff --git a/actionview/test/template/template_error_test.rb b/actionview/test/template/template_error_test.rb index 3971ec809c..54c1d53b60 100644 --- a/actionview/test/template/template_error_test.rb +++ b/actionview/test/template/template_error_test.rb @@ -2,19 +2,34 @@ require "abstract_unit" class TemplateErrorTest < ActiveSupport::TestCase def test_provides_original_message - error = ActionView::Template::Error.new("test", Exception.new("original")) + error = begin + raise Exception.new("original") + rescue Exception + raise ActionView::Template::Error.new("test") rescue $! + end + assert_equal "original", error.message end def test_provides_original_backtrace - original_exception = Exception.new - original_exception.set_backtrace(%W[ foo bar baz ]) - error = ActionView::Template::Error.new("test", original_exception) + error = begin + original_exception = Exception.new + original_exception.set_backtrace(%W[ foo bar baz ]) + raise original_exception + rescue Exception + raise ActionView::Template::Error.new("test") rescue $! + end + assert_equal %W[ foo bar baz ], error.backtrace end def test_provides_useful_inspect - error = ActionView::Template::Error.new("test", Exception.new("original")) + error = begin + raise Exception.new("original") + rescue Exception + raise ActionView::Template::Error.new("test") rescue $! + end + assert_equal "#<ActionView::Template::Error: original>", error.inspect end end diff --git a/activejob/lib/active_job/arguments.rb b/activejob/lib/active_job/arguments.rb index 8e462bfe5d..e56bc79328 100644 --- a/activejob/lib/active_job/arguments.rb +++ b/activejob/lib/active_job/arguments.rb @@ -3,16 +3,23 @@ require 'active_support/core_ext/hash' module ActiveJob # Raised when an exception is raised during job arguments deserialization. # - # Wraps the original exception raised as +original_exception+. + # Wraps the original exception raised as +cause+. class DeserializationError < StandardError + def initialize(e = nil) #:nodoc: + if e + ActiveSupport::Deprecation.warn("Passing #original_exception is deprecated and has no effect. " \ + "Exceptions will automatically capture the original exception.", caller) + end + + super("Error while trying to deserialize arguments: #{$!.message}") + set_backtrace $!.backtrace + end + # The original exception that was raised during deserialization of job # arguments. - attr_reader :original_exception - - def initialize(e) #:nodoc: - super("Error while trying to deserialize arguments: #{e.message}") - @original_exception = e - set_backtrace e.backtrace + def original_exception + ActiveSupport::Deprecation.warn("#original_exception is deprecated. Use #cause instead.", caller) + cause end end @@ -41,8 +48,8 @@ module ActiveJob # All other types are deserialized using GlobalID. def deserialize(arguments) arguments.map { |argument| deserialize_argument(argument) } - rescue => e - raise DeserializationError.new(e) + rescue + raise DeserializationError end private diff --git a/activejob/test/jobs/rescue_job.rb b/activejob/test/jobs/rescue_job.rb index f1b9c9349e..4f6376c850 100644 --- a/activejob/test/jobs/rescue_job.rb +++ b/activejob/test/jobs/rescue_job.rb @@ -11,7 +11,7 @@ class RescueJob < ActiveJob::Base rescue_from(ActiveJob::DeserializationError) do |e| JobBuffer.add('rescued from DeserializationError') - JobBuffer.add("DeserializationError original exception was #{e.original_exception.class.name}") + JobBuffer.add("DeserializationError original exception was #{e.cause.class.name}") end def perform(person = "david") diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index f5b2e9fa9d..55910865e5 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -538,7 +538,7 @@ module ActiveRecord def translate_exception(exception, message) # override in derived class - ActiveRecord::StatementInvalid.new(message, exception) + ActiveRecord::StatementInvalid.new(message) end def without_prepared_statement?(binds) diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index b775c18c1b..3e3bbc267b 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -867,9 +867,9 @@ module ActiveRecord def translate_exception(exception, message) case error_number(exception) when 1062 - RecordNotUnique.new(message, exception) + RecordNotUnique.new(message) when 1452 - InvalidForeignKey.new(message, exception) + InvalidForeignKey.new(message) else super end diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index 42c4a14f00..773ecbe126 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -20,7 +20,7 @@ module ActiveRecord ConnectionAdapters::Mysql2Adapter.new(client, logger, options, config) rescue Mysql2::Error => error if error.message.include?("Unknown database") - raise ActiveRecord::NoDatabaseError.new(error.message, error) + raise ActiveRecord::NoDatabaseError else raise end diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index fddb318553..89d18ee14e 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -38,7 +38,7 @@ module ActiveRecord ConnectionAdapters::MysqlAdapter.new(mysql, logger, options, config) rescue Mysql::Error => error if error.message.include?("Unknown database") - raise ActiveRecord::NoDatabaseError.new(error.message, error) + raise ActiveRecord::NoDatabaseError else raise end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 6200cc8d29..ed6ab8235f 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -402,9 +402,9 @@ module ActiveRecord case exception.result.try(:error_field, PGresult::PG_DIAG_SQLSTATE) when UNIQUE_VIOLATION - RecordNotUnique.new(message, exception) + RecordNotUnique.new(message) when FOREIGN_KEY_VIOLATION - InvalidForeignKey.new(message, exception) + InvalidForeignKey.new(message) else super end @@ -589,7 +589,7 @@ module ActiveRecord @connection.exec_prepared(stmt_key, type_casted_binds) end rescue ActiveRecord::StatementInvalid => e - pgerror = e.original_exception + pgerror = e.cause # Get the PG code for the failure. Annoyingly, the code for # prepared statements whose return value may have changed is @@ -645,7 +645,7 @@ module ActiveRecord configure_connection rescue ::PG::Error => error if error.message.include?("does not exist") - raise ActiveRecord::NoDatabaseError.new(error.message, error) + raise ActiveRecord::NoDatabaseError else raise end diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index 9028c1fcb9..32fe275bfb 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -33,7 +33,7 @@ module ActiveRecord ConnectionAdapters::SQLite3Adapter.new(db, logger, nil, config) rescue Errno::ENOENT => error if error.message.include?("No such file or directory") - raise ActiveRecord::NoDatabaseError.new(error.message, error) + raise ActiveRecord::NoDatabaseError else raise end @@ -559,7 +559,7 @@ module ActiveRecord # Older versions of SQLite return: # column *column_name* is not unique when /column(s)? .* (is|are) not unique/, /UNIQUE constraint failed: .*/ - RecordNotUnique.new(message, exception) + RecordNotUnique.new(message) else super end diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index 142b6e8599..1250f8a3c3 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -193,8 +193,8 @@ module ActiveRecord } begin statement.execute(hash.values, self, connection).first - rescue TypeError => e - raise ActiveRecord::StatementInvalid.new(e.message, e) + rescue TypeError + raise ActiveRecord::StatementInvalid rescue RangeError nil end diff --git a/activerecord/lib/active_record/errors.rb b/activerecord/lib/active_record/errors.rb index 533c86a6a9..1cd2c2ef8c 100644 --- a/activerecord/lib/active_record/errors.rb +++ b/activerecord/lib/active_record/errors.rb @@ -94,13 +94,21 @@ module ActiveRecord # Superclass for all database execution errors. # - # Wraps the underlying database error as +original_exception+. + # Wraps the underlying database error as +cause+. class StatementInvalid < ActiveRecordError - attr_reader :original_exception def initialize(message = nil, original_exception = nil) - @original_exception = original_exception - super(message) + if original_exception + ActiveSupport::Deprecation.warn("Passing #original_exception is deprecated and has no effect. " \ + "Exceptions will automatically capture the original exception.", caller) + end + + super(message || $!.try(:message)) + end + + def original_exception + ActiveSupport::Deprecation.warn("#original_exception is deprecated. Use #cause instead.", caller) + cause end end diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index 62579a4a7a..77c47f12d5 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -151,14 +151,16 @@ module ActiveRecord def test_uniqueness_violations_are_translated_to_specific_exception @connection.execute "INSERT INTO subscribers(nick) VALUES('me')" - assert_raises(ActiveRecord::RecordNotUnique) do + error = assert_raises(ActiveRecord::RecordNotUnique) do @connection.execute "INSERT INTO subscribers(nick) VALUES('me')" end + + assert_not_nil error.cause end unless current_adapter?(:SQLite3Adapter) def test_foreign_key_violations_are_translated_to_specific_exception - assert_raises(ActiveRecord::InvalidForeignKey) do + error = assert_raises(ActiveRecord::InvalidForeignKey) do # Oracle adapter uses prefetched primary key values from sequence and passes them to connection adapter insert method if @connection.prefetch_primary_key? id_value = @connection.next_sequence_value(@connection.default_sequence_name("fk_test_has_fk", "id")) @@ -167,6 +169,8 @@ module ActiveRecord @connection.execute "INSERT INTO fk_test_has_fk (fk_id) VALUES (0)" end end + + assert_not_nil error.cause end def test_foreign_key_violations_are_translated_to_specific_exception_with_validate_false @@ -174,11 +178,13 @@ module ActiveRecord self.table_name = 'fk_test_has_fk' end - assert_raises(ActiveRecord::InvalidForeignKey) do + error = assert_raises(ActiveRecord::InvalidForeignKey) do has_fk = klass_has_fk.new has_fk.fk_id = 1231231231 has_fk.save(validate: false) end + + assert_not_nil error.cause end end @@ -231,11 +237,13 @@ module ActiveRecord unless current_adapter?(:PostgreSQLAdapter) def test_log_invalid_encoding - assert_raise ActiveRecord::StatementInvalid do + error = assert_raise ActiveRecord::StatementInvalid do @connection.send :log, "SELECT 'ы' FROM DUAL" do raise 'ы'.force_encoding(Encoding::ASCII_8BIT) end end + + assert_not_nil error.cause end end end diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb index 31686bde3f..acc3103ac6 100644 --- a/activerecord/test/cases/persistence_test.rb +++ b/activerecord/test/cases/persistence_test.rb @@ -744,9 +744,10 @@ class PersistenceTest < ActiveRecord::TestCase assert !topic.approved? assert_equal "The First Topic", topic.title - assert_raise(ActiveRecord::RecordNotUnique, ActiveRecord::StatementInvalid) do + error = assert_raise(ActiveRecord::RecordNotUnique, ActiveRecord::StatementInvalid) do topic.update_attributes(id: 3, title: "Hm is it possible?") end + assert_not_nil error.cause assert_not_equal "Hm is it possible?", Topic.find(3).title topic.update_attributes(id: 1234) |