2

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.

lyonsinbeta
  • 919
  • 6
  • 25
  • Can you post some code? When you accessible from the layout, what do you mean? Would that data in the YAML file always be current? – Beartech Jan 26 '15 at 23:17
  • By "accessible from the layout" I mean I want a layout to include data that the template knows about. Example: the template has author information for a blog post, then the layout has a sidebar with information about that author. The layout would need to know author information declared in the template. As or "always current" I'm not sure exactly what you mean but my gut instinct is, yes it would be. The data in this YAML file would not change frequently. – lyonsinbeta Jan 27 '15 at 00:43
  • 1
    Better use `@data` instead of `data` – dddd1919 Jan 27 '15 at 02:11
  • I cannot believe that it was that simple. Thank you so much. From this day forward I will sing the name of @dddd1919 in the highest honor. – lyonsinbeta Jan 27 '15 at 02:37
  • BTW, set this logic operation in template is not a good way, better place to controller or helper – dddd1919 Jan 27 '15 at 03:03
  • @dddd1919 I know variables can be passed from `config.rb` to template/layouts via `page do` blocks and `helpers` but I have to declare them in the template because I have multiple "blogs" and need different data for each blog template to be passed to the same layout. The answer you gave me works great. Is there some reason _not_ to do it that way? – lyonsinbeta Jan 27 '15 at 03:07
  • Just a default convention in rails. Although not one way can achieve this goal, but helper can do it better for your mates to understande your idea. – dddd1919 Jan 27 '15 at 04:02
  • Any reason you're not using Middlemans built-in [local data capabilities](https://middlemanapp.com/advanced/local-data/) or the [frontmatter](https://middlemanapp.com/basics/frontmatter/)? A combination of those should fit your use case. – Volker Rose Jan 27 '15 at 10:06

1 Answers1

3

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.

Community
  • 1
  • 1
lyonsinbeta
  • 919
  • 6
  • 25
  • Sounds very nice, thought it would be great if there were a way to evaluate the variables? Say for instance you add a partial path in your yaml file, it would be nice get the content already pre-processed. – Andrea Moro Feb 01 '15 at 10:02