Reading data files from data file

I want to have a top-level data file that contains the names of other data files. So the top-level file will have something like

  • gallery: “gallery1”
  • gallery: “gallery2”

and in gallery1.yml, I would have

  • title: “Gallery 1”

What I would like to do is use proxies to generate gallery1.html, using locals to pass in the name of the
gallery data file, and then in the gallery template, use something like

<%= f=locals[:gallery_name] %>
<%= data.f.title %>

Is this possible at all? Or does everything need to be all in one data file?

Thanks

Simon

As a sidenote: according to docs you usually read data files with the data.filename.object format (i.e.: data.gallery1.title), but it’s also possible to use the array format: data[filename].object which is handy if you somehow compute that name or extract it from other objects.

Also, there is no need to use gallery: "gallery1" named-property format. Just plain array will do:

- "gallery1"
- "gallery2"

if your masterfile only lists filenames of datafiles. And this format is expected by the code below. Back to the point. You can extract the names of data files from a master data file master_list.yml:

data.master_list.each do |datafile|
  data.datafile.title # title extracted from gallery1.yml, gallery2.yml, …
  data.datafile.description # etc
end

So the code for generating proxies would be like:

data.master_list.each do |datafile|
  proxy "/gallery/#{data.datafile.slug}.html", "/gallery/template.erb", locals: {localdata: data.datafile}, ignore: true
end

Pay attention that each datafile should include the field slug, to use that code, and as local variable localdata you get the whole data from a single datafile.

@komor72 I’m trying this out as you’ve listed, but I’m not sure if I have something wrong. In my config.rb I have:

data.masterlist.each do |datafile|
  proxy "/#{data[datafile].slug}.html", "/index.html", locals: { localdata: data[datafile] }, ignore: true
end

I have a data/masterlist.yaml file that contains:

- "galveston-tx"
- "miami-fl"
- "losangeles-ca"

and I have three identical files, but with their respective names/values like:
in data/miami-fl.yaml

slug: "miami-fl"
location: "Miami, Florida"

but when I load up localhost:4567/miami-fl.html, I get this error in my browser window:

File Not Found
/miami-fl.html

Thoughts?

What your http://localhost:4567/__middleman/sitemap/ shows? I have something similar in one of my projects (old Middleman 3.4.1), but with a twist – I18n wariants of every page. In my config.rb:

# Dynamically generated pages for websites, based on /data/websites.yml

after_configuration do
	langs.each do |l|
		lang = (l == I18n.default_locale) ? ('') : (l.to_s + '/')
		data.websites.each do |site|
			if site.pages.include?("portfolio")
				proxy "#{lang}portfolio/#{site.url}.html", "portfolio/website.html", :locals => { :site => site }, :ignore => true do I18n.locale = l end
			end
		end
	end

end

Take notice of after_configuration do. This is probably needed in Middleman 3, not needed in v4. My

According to my Gemfile, it looks like I’m using gem middleman '~>4.2'

Additionally, it looks like it just gets hung up a bit in the translation. For example, if I do this in the console (similar to what I’m doing in my config.rb file above), I do get what I expect:

[3] pry(#<Middleman::Application>)> data.masterlist.each do |datafile|
[3] pry(#<Middleman::Application>)*   puts data[datafile]
[3] pry(#<Middleman::Application>)* end
#<Middleman::Util::EnhancedHash location="Miami, Florida" slug="miami-fl">
#<Middleman::Util::EnhancedHash location="Galveston, Texas" slug="galveston-tx">
#<Middleman::Util::EnhancedHash location="Los Angeles, California" slug="losangeles-ca">

I just tried doing this and got a new error:

["miami-fl", "galveston-tx", "losangeles-ca"].each do |slug|
  proxy "/#{slug}.html", "/index.html", :locals => { :localdata => data[slug] }, :ignore => true
end

and the resulting error:

TypeError at /miami-fl.html
can't convert Middleman::CoreExtensions::Collections::LazyCollectorStep to String (Middleman::CoreExtensions::Collections::LazyCollectorStep#to_str gives Middleman::CoreExtensions::Collections::LazyCollectorStep)

and the offending line:

<h1 class="title is-1"><%= localdata.location %></h1>

Weird. Looking at sitemap the pages are created, but slug is not read correctly, so you have object LazyCollectorStep instead of string. Maybe create a simple index.html.erb file and print out your loop content:

<% data.masterlist.each do |datafile| %>
<p><%= data[datafile].slug %>
<% end %>

Try some .inspect?

One more thing drew my attention: your proxy-template is named index.html which kind of has special meaning in HTTP world. Try to rename your proxy-template?

So it looks like you were onto something with the index.html name. I didn’t think that would change much, but the page actually loaded. What I’m finding is that this works:

["miami-fl", "galveston-tx", "losangeles-ca"].each do |datafile|
  proxy "/#{datafile}.html", "/main.html", locals: { localdata: data[datafile] }, ignore: true
end

and this does not work for me:

data.masterlist.each do |datafile|
  proxy "/#{data[datafile].slug}.html", "/main.html", locals: { localdata: data[datafile] }, ignore: true
end

I don’t really know why, because they’re pretty much the same thing.

Additionally, locals aren’t working at all for me as well as the CSS isn’t getting loaded, so I lose all of my stylings. Any thoughts on why? Do I need something different set up in my config.rb file?

Hard to guess with no further info, files, etc. Try to .inspect things or play with the console. Try to inspect locals inside the template?

Thanks @komor72 I think I got it figured out from here! I appreciate the insight!