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
Better handle SyntaxError in Action View #48957
Conversation
cc: @tenderlove, @byroot |
end | ||
|
||
def error_originated_in_eval_block? | ||
__getobj__.to_s.match?(/^\(eval\)/) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
__getobj__.to_s.match?(/^\(eval\)/) | |
__getobj__.to_s.start_with?("(eval") |
This won't match anymore in 3.3: https://bugs.ruby-lang.org/issues/19755
yarn.lock
Outdated
"@rails/activestorage@>= 7.0.0-alpha1": | ||
version "7.0.4" | ||
resolved "https://registry.yarnpkg.com/@rails/activestorage/-/activestorage-7.0.4.tgz#56bc3052f60e8867b40a87ed5ff3c0afe536643e" | ||
integrity sha512-K2fV9C0z88fapu58nt9uHzMylsmJWUFuaIFvuZQEf1WTiPMsgTsj1bf8+cD81zXfTXYMZDQNRq4164JmuBKD3A== | ||
dependencies: | ||
spark-md5 "^3.0.1" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is unrelated to your PR.
@@ -9,4 +9,7 @@ def spot(ex) | |||
def spot(ex) | |||
end | |||
end | |||
def thread_backtrace_location |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def thread_backtrace_location | |
def thread_backtrace_location |
I don't like the idea of adding a core_ext for this.
I'd rather use is_a?
in the caller. Polymorphism is nicer indeed, but not at the cost of reopening a core class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @byroot!
I can change the logic to use is_a?
, but I wanted to keep in line with the spirit of #46171 where Thread::Backtrace::Location
has been monkey patched.
My fear is that if I change this code to use is_a?
, then this is not consistent with the rest of the code, which is instead relying on Thread::Backtrace::Location
being monkey patched.
I am happy to use is_a?
but I wanted to hear your thoughts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I disagree with how @tenderlove implemented it, I think it would have been possible to not add that Location#spot
method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I disagree with how @tenderlove implemented it, I think it would have been possible to not add that
Location#spot
method.
If you want to refactor, I'm fine with it! 😂
One alternative would be to implement itself
on BacktraceLocationProxy
. Then we wouldn't need to add another method to Thread::Backtrace::Location
TBH, I think this def spot(ex)
monkey patch should actually be part of ErrorHighlight. ErrorHighlight only works with BacktraceLocation objects, so the double dispatch / factory pattern makes sense to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you want to refactor, I'm fine with it! 😂
I know :)
I'll see if get some time to avoid that patch, in the meantime I think we should mark many of this stuff as private API: https://edgeapi.rubyonrails.org/classes/Thread/Backtrace/Location.html#method-i-spot
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks guys!
I have made the following changes to exception_wrapper.rb
:
- Before calling
spot
on the template object, check if we have a real Thread::Backtrace::Location object to prevent calling MRI with the wrong object; - When building the SourceMapLocation object, ensure that we are passing a Thread::Backtrace::Location object and not a BacktraceLocationProxy object
bde1b0e
to
4598f41
Compare
end | ||
|
||
def error_originated_in_eval_block? | ||
__getobj__.to_s.start_with?("(eval") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
__getobj__.to_s.start_with?("(eval") | |
__getobj__.path.start_with?("(eval") |
Using path
is simpler than rendering Location#to_s
. Also I'm not convinced this method extraction is really worth it.
@cmaruz Build is failing, could you take a look? 🙇 https://buildkite.com/rails/rails/builds/99163#018a3c4e-42cc-4132-baf4-58d424793ac3/1066-1255
|
a92ce81
to
e6c5f41
Compare
Hi @zzak, I fixed the failing test - it was due to the fact that in Ruby versions prior to 3.3, |
dd62149
to
016a256
Compare
It depends, but generally speaking we try to check for it at definition time rather than rutime. So in your case it could be: if SyntaxError.method_defined?(:path) # Ruby 3.3+
def parse_message_for_trace
# 3.3+ version of the method
end
else
def parse_message_for_trace
# 3.2 and older version of the method
end
end |
de733f3
to
ac45315
Compare
Thanks @byroot, I have changed the check to be at definition time. Please let me know what you think! |
method cause an Internal Server Error due to a TypeError. In order to display the extraced source of a syntax error, we try to locate the node id for the backtrace location. The call to RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location is expecting a Thread::Backtrace::Location object, but we are passing a SourceMapLocation instead. This commit does two things: 1) it addresses the issue by making sure that we are always passing a Thread::Backtrace::Location instead 2) it allows the development view to show the extracted source fragment
I squashed the commits into a single commit and I think this PR is ready to go - the build failure seems to be unrelated and tests pass locally. Please let me know if you have more feedback! |
Better handle SyntaxError in Action View
Backported to 7-1-stable in b02f6c9. |
Motivation / Background
Fixes #48326
This Pull Request has been created to fix an issue where syntax errors generated inside an eval method cause an Internal Server Error due to a TypeError.
Detail
In order to display the extraced source of a syntax error, we try to locate the node id for the backtrace location. The call to RubyVM::AbstractSyntaxTree.node_id_for_backtrace_location is expecting a Thread::Backtrace::Location object, but we are passing a SourceMapLocation instead.
Once this is fixed, another issue then appears. The first location of the backtrace for an eval error does not include the filename of where eval is called, so we can't extract the source. This means that the development view fails to show the extracted source because it is hard-coded to show the source extracted for the first location.
This commit does two things:
Additional information
I have tried to keep the changes consistent with the approach introduced in #46171.