Skip to content

Fix line numbers and empty output for ERB templates Rails doesn't annotate - #2716

Merged
joelhawksley merged 1 commit into
ViewComponent:mainfrom
mizoR:fix-erb-newline-compensation-for-unannotated-templates
Sep 14, 2026
Merged

Fix line numbers and empty output for ERB templates Rails doesn't annotate#2716
joelhawksley merged 1 commit into
ViewComponent:mainfrom
mizoR:fix-erb-newline-compensation-for-unannotated-templates

Conversation

@mizoR

@mizoR mizoR commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Rails 8.1 added a newline to compiled ERB output (rails/rails#53731), and #2502 compensates for it on every ERB template. But Rails only adds that newline when it emits the <!-- BEGIN ... --> annotation:

# actionview/lib/action_view/template/handlers/erb.rb
if ActionView::Base.annotate_rendered_view_with_filenames && template.format == :html

Line numbers in backtraces are off by one for .text.erb and .css.erb templates, and for all ERB templates when annotations are off, which is the default in production.

Under coverage, non-HTML templates render empty. The annotation stripping from #2541 / #2552 checks the annotation setting but not the format, so it cuts into the template body.

Fix

Move both conditions into erb_newline_compensation_needed? on Template. lineno is still never negative while coverage is running.

Template::Inline had the same off-by-one. It also picked its lineno when the class was defined instead of when it compiled, so it now uses the shared predicate at compile time like Template::File.

Notes

without_template_annotations was missing an ensure, so an exception escaping the block left annotations off for the rest of the process.

Tested on Rails 8.1.3.1 / Ruby 4.0.6. I haven't run the full appraisal matrix. Rails < 8.1 is unaffected.

Rails 8.1 added a newline to compiled ERB output (rails/rails#53731), and
ViewComponent compensates with a lineno of -1 so backtraces point at the
right line. That newline lives inside the `<!-- BEGIN ... -->` annotation,
which Rails only prepends when `annotate_rendered_view_with_filenames` is
enabled *and* the template's format is HTML.

Compensating for every ERB template shifted backtraces by one line for
non-HTML templates (`.text.erb`, `.css.erb`) and for every ERB template
when annotations are disabled, such as in production. When coverage was
running, the same mismatch made `strip_annotation_line?` drop everything
up to the first `;` of a preamble that was never emitted, so non-HTML
templates rendered empty.

Move the annotation conditions into `erb_newline_compensation_needed?` on
`Template` so every call site fires exactly when Rails emits the
annotation. The negative lineno is still avoided under coverage
(bugs.ruby-lang.org/issues/19363).

`Template::Inline` had the same off-by-one, and decided the compensation
when the component class was defined rather than when it compiled. It now
shares the predicate and resolves it at compile time, matching
`Template::File`.

Also add the missing `ensure` to the `without_template_annotations` test
helper, so an exception escaping the block no longer leaves annotations
disabled for the rest of the process.
@joelhawksley
joelhawksley merged commit 9bad91a into ViewComponent:main Sep 14, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants