Passing local data variables between layout and te

2019-07-20 06:00发布

问题:

I need to be able to share local data (in a yaml file) from templates with a layout. I want to be able to load relevant YAML data in the template then have that data be accessible from the layout (and associated partials). Is this possible?

I found this blog post which seems to indicate that this is possible through some shennaigans but I can't get it to work and this seems hacky. Is there a built in way to pass data between templates and layouts? And if not, can the hack in this blog post be made to work?

Update: now featuring code!

Here is code from the blog post linked above. I tried it exactly as show, and played with it a little, but no dice.

# in your layout file (inside layout/ folder):
<% myvar = yield_content :myvar %>
<% myvar = eval(myvar.to_str) %>

# in your template file (e.g., mypage.html.erb):
<% content_for :myvar, data.somefile %>

# this examples assumes there's a somefile.yml in your data/ folder:
name: hello world
tag: the quick brown jumps over the lazy dog

The above code returned no implicit conversion of nil into String which sounds like the YAML file either didn't load or was't passed to the layout (since it's loaded in the template.) I confirmed it was loading in the template so maybe it wasn't being passed to the template for some reason? (Aside: as a new programmer I've been taught eval is the devil's work and to "never use it" so this solution seems sketchy to me.)

On my own I tried to do something like the below, and if the YAML is loaded into the template like so:

data = YAML.load_file('some/file/data.yml')

it works fine within the template but the layout throws undefined local variable errors.

The same, but reverse, is true if you load the YAML into the layout, it won't be accessible in the template. Additionally, I don't want the data loaded in the layout because it will be different depending on the template it's coming from.

Ideally I would just pass the loaded YAML data from the template to the layout, but I think I could also achieve my ultimate goal if the layout new for which blog (it's a multi blog site) it was being called on. However after talking with some people on the Middleman team that route does not appear to be an option.

回答1:

It turns out all you have to do to pass data from a template to a layout is declare an instance variable. So for YAML data like I was doing:

# In your template
<% @my_var = YAML.load_file("path/to/data.yml") %>

# In your layout
<p>My_var contains: <%= @my_var %></p>

I don't know if this is obvious if you're familiar with the tool chain underneath middleman, or if it's in the documentation somewhere and I just couldn't find it, but that's all there is to it.

Thanks so much to @dddd1919 for dropping this knowledge bomb.