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

Add column information inside ERB templates #46171

Merged
merged 21 commits into from Oct 11, 2022
Merged

Add column information inside ERB templates #46171

merged 21 commits into from Oct 11, 2022

Conversation

tenderlove
Copy link
Member

@tenderlove tenderlove commented Oct 1, 2022

This PR builds on the work done in #45818. It adds column information to exceptions that occur inside ERB templates. Here are some "before" and "after" screenshots.

Before:

Action Controller: Exception caught 2022-10-01 15-41-36

After:

Action Controller: Exception caught 2022-10-01 15-42-08

In order to accomplish this, I changed the error handling internals to always deal with backtrace locations. Before this PR, the exception wrapper class would sometimes use backtrace_locations and sometimes use backtrace. ErrorHighlight only works with backtrace locations objects, so I refactored the code to only use backtrace locations objects.

Unfortunately that refactoring process was somewhat difficult due to the way we handle SyntaxError exceptions. SyntaxError exceptions do not contain the location of the syntax error in the backtrace. Because of that, we would mutate the backtrace. We need to maintain the same SyntaxError behavior, but mutating the backtrace doesn't seem like a good idea, so this PR introduces a SyntaxError wrapper object that implements backtrace and backtrace_locations.

The next challenge is that ErrorHighlight will only work with Exceptions and with Thread::Backtrace::Location objects. And clearly the above code introduces backtrace location objects that aren't instances of Thread::Backtrace::Location. I didn't want to do is_a? checks in the exception wrapper code, so I added a monkeypatch to Thread::Backtrace::Location that returns the spot information from ErrorHighlight if it's available. This lets us do something special in the SyntaxError case, though it doesn't right now.

Now that actual backtrace location objects are returned, ErrorHighlight worked with ERB, but it would report the compiled ERB source rather than the template source. For example we'd see this, which is wrong:

index html erb (~:git:blogsite:app:views:posts) - VIM5 2022-09-28 16-44-42

To deal with this, I added a global hash table that maps method names to template objects here. When the exception wrapper gets the backtrace, it checks if the method was a "template" method and returns a special backtrace object. The special backtrace object simply asks the template to map the ErrorHighlight source to the actual source. The template object just turns around and asks the handler to do the mapping. The handler will be the actual template strategy (ERB, HAML, etc).

ERB translation happens here. It's kind of hacky but seems to work.

There's a few things I need to do before I consider this PR mergeable:

  1. I need to add tests for the ERB parsing code I added. I have the tests in a separate file, just haven't put them in this PR yet.
  2. The ERROR_HANDLERS hash is probably a memory leak in development. I'm not sure how to handle that yet.
  3. I'm not sure if there are any "integration" type tests with the column info from ERB. I need to add those.
  4. I think there's some cosmetic stuff I need to clean up in the code.

I'd really appreciate help with the second item.

We are currently mutating exception objects and I would like to stop
doing that.  Unfortunately the views are calling many methods directly
on the exception and expecting that the mutations exist.

This patch refactors the templates so that they ask the ExceptionWrapper
class for information about the exception rather than directly asking
the exception object itself
This commit adds a SyntaxErrorProxy object to active support and wraps
syntax error exceptions with that proxy object.  We want to enhance
syntax errors with information about the source location where they
actually happened (normally the backtrace doesn't contain such info).
Rather than mutating the original exception's backtrace, this wraps it
with a proxy object.

Eventually we will implement backtrace_locations on the proxy object so
that the exception handling middleware can be updated to _only_ deal
with backtrace_locations and never deal with raw `backtrace`
We should get out of the business of parsing backtraces and only use
backtrace locations.  Backtrace locations have the file and line number
information baked in, so we don't need to parse things anymore
This way we can do special stuff when the exceptions come from special
locations
This commit maps the column information returned from ErrorHighlight in
to column information within the source ERB template.  ErrorHighlight
only understands the compiled Ruby code, so this commit adds a small
translation layer that converts the values from ErrorHighlight in to the
right values for the ERB source template
We have access to the path from the backtrace location object.  If we
use the path of the ERB as the key, then anytime the ERB changes it'll
just overwrite that template instance in the error handling hash
This isn't as easy, but should eliminate any memory leaks in dev
@tenderlove tenderlove marked this pull request as ready for review October 10, 2022 02:20
@rails-bot rails-bot bot added the railties label Oct 11, 2022
@tenderlove tenderlove merged commit 2f36f0a into main Oct 11, 2022
@tenderlove tenderlove deleted the refactor-errors branch October 11, 2022 22:10
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.

None yet

1 participant