Skip to content
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

Locals aren't rendered in the layout (render plugin) #80

Closed
jrgns opened this issue Jul 24, 2016 · 9 comments
Closed

Locals aren't rendered in the layout (render plugin) #80

jrgns opened this issue Jul 24, 2016 · 9 comments

Comments

@jrgns
Copy link

jrgns commented Jul 24, 2016

Given the following app:

# app.rb
require 'roda'

class App < Roda
  plugin :render

  route do |r|
    r.root do
      @instance = 'Instance Var'
      view 'test', locals: { local: 'Local Var' }
    end
  end
end
#views/layout.erb
<html><body>
<h2>Layout</h2>
<p>
Instance: <%= defined?(@instance) ? @instance : 'None'  %><br>
Local: <%= defined?(local) ? local : 'None' %>
</p>

<%= yield %>
</body></html>
#views/test.erb
<h2>View</h2>

<p>
Instance: <%= defined?(@instance) ? @instance : 'None'  %><br>
Local: <%= defined?(local) ? local : 'None' %>
</p>

The outcome is:

Layout

Instance: Instance Var
Local: None

View

Instance: Instance Var
Local: Local Var

Instead of

Layout

Instance: Instance Var
Local: Local Var

View

Instance: Instance Var
Local: Local Var

@jeremyevans
Copy link
Owner

This is the expected and specified behavior. You need to pass layout options via :layout_opts (e.g. layout_opts:{ locals: { local: 'Local Var' }}). This allows you to specify different locals to the layout than to the view itself.

I suppose we could consider an option (off by default) to the render plugin that would automatically merge the view template :locals into the layout template :locals. I can probably work on that before the next release.

@jrgns
Copy link
Author

jrgns commented Jul 25, 2016

Cool. It is somewhat confusing if you're coming from sinatra or something similiar where the passed variables are available in both the layout and the template.

My specific use case is to have the same value in the title tag and somewhere on the page.

I saw the layout_opts option, but didn't realize that locals can be passed to the layout specifically. Maybe just make it clearer in the docs?

@jeremyevans
Copy link
Owner

I can definitely see where it can cause issues. It's not a problem if you pass data to the view implicitly via instance variables (like sinatra, view scope is the same as route scope), but some people prefer the more explicit approach by specifying locals.

I'll improve the docs as well, but I do think it would be good to support using :locals for both the view template and layout template via an option.

@janko
Copy link

janko commented Jul 25, 2016

How about :locals being automatically passed to the layout template, and any locals specified in :layout_opts would be merged with :locals, overriding variables with the same name? I think this would satisfy both requirements, and wouldn't bring any backwards incompatibility.

@jeremyevans
Copy link
Owner

That's basically what the option would do. It can't be the default behavior (at least not till Roda 3), as it would affect backwards compatibility.

With this option, here is how I'm planning to populate locals, in terms of priority (least to greatest):

  • Plugin :locals
  • Plugin :layout_opts => :locals
  • method :locals
  • method :layout_opts => :locals

@jrgns
Copy link
Author

jrgns commented Jul 25, 2016

Sounds great.

@jrgns
Copy link
Author

jrgns commented Jul 26, 2016

Thanx!

Further to this, I see that the locals passed to a template / layout aren't inherited by partials either. Is this intentional, or an omission?

The workaround is to obviously pass the locals to the partial call:

<%= partial('navbar', locals: { title: title }) %>

@jeremyevans
Copy link
Owner

That is intentional. Note that templates are cached per combination of locals, so just blinding merging locals into partials could lead to increased memory usage (possibly combinatoric memory usage in edge cases with nested partials).

You could probably use the view_options plugin, which allows you to set locals in one place and use them for all template renders.

@jrgns
Copy link
Author

jrgns commented Jul 27, 2016

Cool, thanx, looks useful.

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

No branches or pull requests

3 participants