Including one erb file into another
Asked Answered
M

4

33

I'm writing a command-line tool that will ultimately output an HTML report. The tool is written in Ruby. (I am not using Rails). I'm trying to keep the logic of the application in one set of files, and the HTML templates (the .erb files) in another set.

I'm having a really annoying problem though: I can't successfully include one .erb file into another.

To be specific, I'm trying to do something like this (in pseudo-code):

<html>
<head>
  <style type='text/css'>
    [include a stylesheet here]
    [and another one here]
  </style>
</head>
<body>
  <p>The rest of my document follows...

That example snippet is itself an erb file, which is being invoked from within the application logic.

I'm doing things this way so I can keep my stylesheets out of the main template to make it easier/cleaner to maintain the application. The end product (the report), though, needs to be a single, stand-alone HTML file which has no dependencies, and thus, I want to inline those stylesheets into the document head when the report is generated.

This seems like this should be easy, but I've been banging my head against a wall (and Googling, and RTMF'ing) for the last hour, and I'm not having any luck at all.

How is this supposed to be done? Thanks.

Mong answered 19/4, 2012 at 20:16 Comment(0)
V
41

ERB templates can be nested by evaluating the sub-template from within <%= %> of the main template.

<%= ERB.new(sub_template_content).result(binding) %>

For example:

require "erb"

class Page
  def initialize title, color
    @title = title
    @color = color
  end

  def render path
    content = File.read(File.expand_path(path))
    t = ERB.new(content)
    t.result(binding)
  end
end

page = Page.new("Home", "#CCCCCC")
puts page.render("home.html.erb")

home.html.erb:

<title><%= @title %></title>
<head>
  <style type="text/css">
<%= render "home.css.erb" %>
  </style>
</head>

home.css.erb:

body {
  background-color: <%= @color %>;
}

produces:

<title>Home</title>
<head>
  <style type="text/css">
body {
  background-color: #CCCCCC;
}
  </style>
</head>
Viola answered 20/4, 2012 at 6:25 Comment(5)
I'm not working in Rails, so I don't think that 'render' stuff applies to me (could be wrong), but that first line worked like a champ. Many thanks!Mong
The render method was defined in the above example using pure std ruby, so it can be used in a rails-free environment. Cheers.Viola
Ha, wow. Don't know how I didn't notice that. Thanks for pointing that out, and thanks for the solution. It worked perfectly.Mong
Related: if you are just including static content you should be able to do something like <%= File.read("common.txt") %>.Crony
The part of the parent template above the call to the sub template would dissapear until I used a fix in @mighq's answer below (and Jack's comment)Chemotherapy
L
18

I'm needing this in a Sinatra app, and I find that I can just call it the same way I called the original:

In the sinatra app, I call the index:

erb :index

Then, in the index template, I can do the same for any sub-template:

<div id="controls">
  <%= erb :controls %>

..which shows the 'controls.erb' template.

Luminal answered 20/5, 2015 at 13:30 Comment(2)
This is definitely the easiest, and therefore the best, answer.Quesenberry
If you pass local vars (erb :index, :locals =>{...}) and you need to pass those local vars along, you can then call <%= erb(:controls, {}, locals)%>Leveridge
E
10
<%= ERB.new(sub_template_content).result(binding) %>

does not work, when you are using erb cli utility, multiple _erbout variables are overriden and only last one is used.

use it like this:

<%= ERB.new(sub_template_content, eoutvar: '_sub01').result(binding) %>
Eligible answered 31/12, 2013 at 11:4 Comment(2)
I needed to do ERB.new(sub_template_context, nil, nil, '_sub01').result(binding) when using test kitchen. It must use an older version of ruby or something.Kazan
I think I was using Ruby 1.8 when adding this answerEligible
A
10

From within my .erb file, I had to do this:

<%= ERB.new(File.read('pathToFile/myFile.erb'), nil, nil, '_sub01').result(binding) %>

The other answers in this thread assumed you had a variable with your content in it. This version retrieves the content.

Alethiaaletta answered 7/7, 2017 at 16:33 Comment(1)
I was able to use this with Test Kitchen. Thanks!Majka

© 2022 - 2024 — McMap. All rights reserved.