Description
Rule: erb-dynamic-partial-path-must-be-static
Description
Disallow string interpolation or dynamic expressions in partial paths passed to render
. The partial path should be a static string known at lint time.
This rule warns when the partial path cannot be reliably determined at lint time. For example, when it includes string interpolation, variable concatenation, or indirect lookup.
Rationale
Dynamic partial paths can lead to:
- Runtime errors (e.g., "Missing partial...")
- Hard-to-debug view rendering behavior
- Difficulties with linters, formatters, and IDEs
- Broken code navigation and static analysis
By requiring partial paths to be static (e.g. "users/user"
), templates become easier to understand, safer to refactor, and tooling can provide better diagnostics and autocomplete and lead to better and more maintainable view code.
To allow dynamic paths when absolutely necessary, you may annotate expected values using an inline comment directive (not sure how that syntax would look like yet).
Examples
✅ Good
<%= render partial: "users/user", collection: @users %>
<%= render partial: "shared/empty_state" %>
🆗 OK
<%= render partial: current_user.admin? ? "admin/header" : "user/header" %>
🚫 Bad
<%= render partial: "users/#{user.role}" %>
<%= render "components/#{component_type}" %>
Annotation ideas:
Maybe we can lean on the Strict Locals
syntax from Rails:
<%# locals: (message: "Hello, world!") -%>
<%# partials: ["users/admin", "users/user"] -%>
<%= render "users/#{user.role}" %>
<%# herb: (partials: ["users/admin", "users/user"]) -%>
<%= render "users/#{user.role}" %>
References
-