Debug mode: Never wrap head-emitting helper output in debug spans - #1953
Draft
kcdragon wants to merge 7 commits into
Draft
Debug mode: Never wrap head-emitting helper output in debug spans#1953kcdragon wants to merge 7 commits into
kcdragon wants to merge 7 commits into
Conversation
A partial rendered into a layout's <head> has no <head> node in its own AST, so the element-stack exclusion in `in_excluded_context?` never fires and helpers like `csrf_meta_tags` or `javascript_include_tag` got wrapped in a `<span style="display: contents;">`. Since <span> is invalid head content, browsers implicitly close </head> there and push the remaining scripts/stylesheets into <body>, breaking Turbo apps. Add a name-based `head_content_helper?` skip (alongside the existing `complex_rails_helper?` guard) covering the standard head helpers and `tag.meta`/`tag.link`/`tag.title`/`tag.base`, and add `meta`, `link`, and `base` to the excluded tags for the inline-in-layout case. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E16jrPfFSya7LHfBXMd5yg
kcdragon
commented
Aug 1, 2026
| false | ||
| end | ||
|
|
||
| # TODO: Rewrite using Prism Nodes once available |
Contributor
Author
There was a problem hiding this comment.
I added this TODO because related methods have this same TODO
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E16jrPfFSya7LHfBXMd5yg
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E16jrPfFSya7LHfBXMd5yg
kcdragon
force-pushed
the
md-skip-head-content-helpers
branch
from
August 1, 2026 21:43
f3f19cd to
5ce00a6
Compare
marcoroth
reviewed
Aug 5, 2026
Comment on lines
+400
to
+411
| head_helpers = [ | ||
| "csrf_meta_tags", | ||
| "csp_meta_tag", | ||
| "viewport_meta_tag", | ||
| "javascript_include_tag", | ||
| "javascript_importmap_tags", | ||
| "stylesheet_link_tag", | ||
| "stylesheet_import_tag", | ||
| "favicon_link_tag", | ||
| "auto_discovery_link_tag", | ||
| "preload_link_tag" | ||
| ] |
Owner
There was a problem hiding this comment.
I wonder if we should add this metadata into our Action View Helper registry in config/action_view_helpers/* so we could dynamically query them.
I added the missing importmap-rails helpers in #2005
Flag helpers whose output belongs in <head> (meta/link/script includes from actionview, actioncable, importmap-rails, and turbo-rails) with head_content: true in their registry YAMLs, and expose them through HelperRegistry.head_content_helpers / head_content?(name) so consumers can query the list instead of hardcoding helper names. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E16jrPfFSya7LHfBXMd5yg
Replace the hardcoded helper name list in head_content_helper? with a pattern built from HelperRegistry.head_content_helpers. This picks up helpers the list missed (action_cable_meta_tag, the turbo-rails meta tag helpers, turbo_include_tags, and the remaining importmap-rails helpers) and drops viewport_meta_tag / stylesheet_import_tag, which don't exist in any registered gem. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E16jrPfFSya7LHfBXMd5yg
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E16jrPfFSya7LHfBXMd5yg
kcdragon
marked this pull request as draft
August 7, 2026 02:50
marcoroth
reviewed
Aug 7, 2026
| gem: "actioncable" | ||
| output: "html" | ||
| visibility: "public" | ||
| head_content: true |
Owner
There was a problem hiding this comment.
@kcdragon I think this is the best thing to do long-term!
Maybe we could reverse it to something like:
context: "head"So other helpers could define other contexts, like:
context: "body"
context: "html"
context: "table"There is also this other pull request which adds more schema-like metadata that could be also useful to have: #1030
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
While using Herb in development, I'm seeing an error from Turbo saying that I'm loading Turbo from a
<script>inside<body>despite it being inside<head>in my source code.app/views/shared/_head.html.erb
Solution
A partial rendered into a layout's has no node in its own AST, so the element-stack exclusion in
in_excluded_context?never fires and helpers likecsrf_meta_tagsorjavascript_include_taggot wrapped in a<span style="display: contents;">. Since is invalid head content, browsers implicitly close there and push the remaining scripts/stylesheets into , breaking Turbo apps.Add a name-based
head_content_helper?skip (alongside the existingcomplex_rails_helper?guard) covering the standard head helpers andtag.meta/tag.link/tag.title/tag.base, and addmeta,link, andbaseto the excluded tags for the inline-in-layout case.Is there a better fix than this?
It seems like it would be impossible to catch all the potential helper methods that belong in
<head>which is the direction this PR is going in. Maybe its good enough for now? It seemed like a fine approach since its similar to the existing check done bycomplex_rails_helper?(code). I'm curious if you know of a better approach.Another option is a herb linter that disscourages
<head>partials but I think those a fairly common especially in apps with multiple layouts.