From e739bcc4ff7c286a61a1eb7ccb42b51ca3cb6b0d Mon Sep 17 00:00:00 2001 From: Kelvin Oghenerhoro Omereshone Date: Mon, 2 Mar 2026 18:31:40 +0100 Subject: [PATCH] fix(inertia-sails): ensure locals are accessible via locals.xxx in EJS templates Sails's default EJS renderer creates an `options.locals` object for internal helpers (blocks, layout, partial). EJS wraps templates in `with(data) { ... }`, which causes `locals` inside the template to resolve to `data.locals` (the Sails-created object) rather than the function parameter containing the actual view data. This made `<%= locals.title %>` always return undefined. Fix by pre-populating `data.locals` with user-provided locals so they survive the `with` scoping. Closes #188 --- packages/inertia-sails/lib/render.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/inertia-sails/lib/render.js b/packages/inertia-sails/lib/render.js index b333c5c0..719afbe1 100644 --- a/packages/inertia-sails/lib/render.js +++ b/packages/inertia-sails/lib/render.js @@ -32,6 +32,15 @@ module.exports = async function render(req, res, data) { return res.json(page) } else { // Implements full page reload - return res.view(rootView, { page, ...allLocals }) + // + // We pass locals both as top-level properties AND nested under a `locals` + // key. This is necessary because Sails's default EJS renderer creates an + // `options.locals` object (for blocks, layout, partial helpers). EJS wraps + // templates in `with(data) { ... }`, so inside the template `locals` + // resolves to `data.locals` (the nested object) rather than the `locals` + // function parameter. By pre-populating `data.locals` with our values, + // `<%= locals.title %>` in the EJS template correctly resolves to the + // dynamic value instead of undefined. + return res.view(rootView, { page, ...allLocals, locals: { ...allLocals } }) } }