Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store original exception in action_dispatch.exception, not exception cause #25623

Closed
wants to merge 1 commit into from
Closed

Store original exception in action_dispatch.exception, not exception cause #25623

wants to merge 1 commit into from

Conversation

greysteil
Copy link
Contributor

@greysteil greysteil commented Jul 1, 2016

Previously, when an error was raised that had a cause, we would store the cause
of the error in request.env["action_dispatch.exception"], rather than the
error itself. That causes a loss of important information - it's not possible
to get back to the top-level error from the stored exception (since the cause
relationship on errors in one-way).

After this change, it is the top-level error, rather than its cause, that will
be stored in request.env["action_dispatch.exception"]. Any exception handler
app can then take responsibility for inspecting the error's cause, if required.

Reverses the (undesired?) change in behaviour from
#18774

In our app, there are a bunch of places where we want to avoid serving 422s for validation errors, and instead want to blow up. The recent change to store the exception's cause means we can no longer do the following:

begin
  # code
rescue ActionRecord::ValidationError => e
  raise "Validation error raised when it should not be possible. Someone should look into this! #{e.message}"
end

@rails-bot
Copy link

r? @sgrif

(@rails-bot has picked a reviewer for you, use r? to override)

@greysteil
Copy link
Contributor Author

@sgrif - any thoughts?

@rafaelfranca
Copy link
Member

r? @jeremy

@rails-bot rails-bot assigned jeremy and unassigned sgrif Jul 5, 2016
@@ -98,7 +98,7 @@ def call(env)

test "calls custom exceptions app" do
exceptions_app = lambda do |env|
assert_kind_of AbstractController::ActionNotFound, env["action_dispatch.exception"]
assert_kind_of ActionView::Template::Error, env["action_dispatch.exception"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#18774 didn't change this assertion; did it really previously contain the outermost exception? 😕

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not in this case - ActionView::Template::Error was a special, and used to store the original_exception (basically its cause), and ExceptionWrapper would use this, rather than the outermost exception. We should be fine for it to change now, though. Just put a comment on the PR explaining.

@matthewd
Copy link
Member

matthewd commented Jul 5, 2016

👍 to the change (or something like it), but I'm unsure about compatibility

@greysteil
Copy link
Contributor Author

greysteil commented Jul 6, 2016

Awesome, thanks @matthewd.

On compatibility, this change would:

  • have no effect for integrators using the standard Rails exception handling apps, since DebugExceptions re-wraps the error anyway, so still render details of its cause, and PublicExceptions doesn't use the exception itself at all
  • change the exception provided to integrators who have defined a custom exception app. The exception would always be the top-level error, rather than its cause. To get back the previous behaviour, they could just wrap the exception in the way it's currently always done in ShowExceptions - something like exception = ActionDispatch::ExceptionWrapper.new(nil, exception).exception.

The undesired change in #18774 was that, previously, when anything other than a few Rails-specific errors were raised (grep for attr_reader :original_exception in that PR to see which ones) as the top-level error, it was the top-level error, not its cause, that was exposed to the exceptions app. After that PR, the top-level error is discarded in favour of its cause whenever that cause has a handler. Hence the loss of the ability to explicitly override the error, as in the code in the description on this PR.

The upside of this change is that with it, integrators can get the current behaviour, but without it it's impossible to get back the old behaviour.

@greysteil
Copy link
Contributor Author

@matthewd any thoughts on the above?

…cause

Previously, when an error was raised that had a cause, we would store the cause
of the error in `request.env["action_dispatch.exception"]`, rather than the
error itself. That causes a loss of important information - it's not possible
to get back to the top-level error from the stored exception (since the `cause`
relationship on errors in one-way).

After this change, it is the top-level error, rather than its cause, that will
be stored in `request.env["action_dispatch.exception"]`. Any exception handler
app can then take responsibilty for inspecting the error's cause, if required.

Reverses the (undesired) change in behaviour from
#18774
@rails-bot
Copy link

rails-bot bot commented Dec 18, 2019

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
Thank you for your contributions.

@rails-bot rails-bot bot added the stale label Dec 18, 2019
@rails-bot rails-bot bot closed this Dec 25, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants