Ruby Templates: How to Pass Variables into Inlined Erb

Ruby templates: How to pass variables into inlined ERB?

Got it!

I create a bindings class

class BindMe
def initialize(key,val)
@key=key
@val=val
end
def get_binding
return binding()
end
end

and pass an instance to ERB

dataHash.keys.each do |current|
key = current.to_s
val = dataHash[key]

# here, I pass the bindings instance to ERB
bindMe = BindMe.new(key,val)

result = template.result(bindMe.get_binding)

# unnecessary code goes here
end

The .erb template file looks like this:

Key: <%= @key %>

Ruby templating: is it possible that only pass some values to variables in template?

You can use double opening %%s to prevent it from being evaluated in erb.

This solution might look ugly but it returns exactly what you want (if it is what you want):

require 'erb'

template = ERB.new <<-EOF
The value of x is: <% if defined?(x) %><%= x %><% else %><%%= x %><% end %>
The value of y is: <% if defined?(y) %><%= y %><% else %><%%= y %><% end %>
EOF
=> #<ERB:0x00007feeec80c428 @safe_level=nil, @src="#coding:UTF-8\n_erbout = +''; _erbout.<<(-\" The value of x is: \"); if defined?(x) ; _erbout.<<(( x ).to_s); else ; _erbout.<<(-\"<%= x %>\"); end ; _erbout.<<(-\"\\n The value of y is: \"\n); if defined?(y) ; _erbout.<<(( y ).to_s); else ; _erbout.<<(-\"<%= y %>\"); end ; _erbout.<<(-\"\\n\"\n); _erbout", @encoding=#<Encoding:UTF-8>, @frozen_string=nil, @filename=nil, @lineno=0>

puts template.result(binding)
The value of x is: <%= x %>
The value of y is: <%= y %>
=> nil

x = 20

puts template.result(binding)
The value of x is: 20
The value of y is: <%= y %>
=> nil

y= 50

puts template.result(binding)
The value of x is: 20
The value of y is: 50
=> nil

I assume you can do the formatting.

Can I pass variables to be rendered by erb from the command line?

As of Ruby 2.2 you can set local variables in Erb from the command line.

You would need to change your code to use local variables rather than instance variables. For example if you had (stripped down from your code):

<VirtualHost <%= http_host %>:<%= http_port %>>

You could then call it with:

$ erb http_host=http://example.com http_port=1234 my_file.erb

and the result would be:

<VirtualHost http://example.com:1234>

Render an ERB template with values from a hash

I don't know if this qualifies as "more elegant" or not:

require 'erb'
require 'ostruct'

class ErbalT < OpenStruct
def render(template)
ERB.new(template).result(binding)
end
end

et = ErbalT.new({ :first => 'Mislav', 'last' => 'Marohnic' })
puts et.render('Name: <%= first %> <%= last %>')

Or from a class method:

class ErbalT < OpenStruct
def self.render_from_hash(t, h)
ErbalT.new(h).render(t)
end

def render(template)
ERB.new(template).result(binding)
end
end

template = 'Name: <%= first %> <%= last %>'
vars = { :first => 'Mislav', 'last' => 'Marohnic' }
puts ErbalT::render_from_hash(template, vars)

(ErbalT has Erb, T for template, and sounds like "herbal tea". Naming things is hard.)

Generate PDF by binding erb template that contains instance variable while sending email

I hope you are rendering the HTML string to generate some PDF / kind of files. In those case, we need to declare the instance variable from where your are invoking those calls. So that it can be accessed through out the request. (Same mailer concepts)

I tried the below one for those cases. It works.

  def generate_attachment(your_variable)
@your_instance_variable = your_variable

attachments['attachment.pdf'] = WickedPdf.new.pdf_from_string(render_to_string(:pdf => "filename.pdf",:template => '/_template.html.erb'))
end

How do you pass an array to an erb template in ruby and have it iterated over?

the basic syntax for using each in ruby is something like this:

array.each do |item_from_array| BLOCK

so if you only had one array then you could just do something like this:
(I would use a different name inside the vertical bars for clarity)

<% device.each do |dev| %>
auto <%= dev %> inet static
<% end %>

However that would iterate over all of your devices first, before moving on to your ipaddr array. I'm guessing you want them each in turn auto, address, netmask, etc. In that case you'd be better off using a more 'traditional' index and looping through N times, like this:

<% for idx in (0..1) %>
auto <%= device[idx] %> inet static
address <%= address[idx] %>
netmask <%= netmask[idx] %>
broadcast <%= broadcast[idx] %>
<% end %>

Of course you need to think about what your maximum size of array is, and what to do if an array contains less entries than the others. You can find the maximum size of all the arrays by doing something like this: [device,address,netmask,broadcast].map{|a| a.length}.max

and you can skip over a particular array like this: <% if idx < address.length %> address <%= address[idx] %><% end %>

Is there a way to limit variable scope in ERB (Ruby)?

As an ERB template is compiled down to a plain Ruby method and is executed as such, you can't restrict its access. Through meta-programming, an author of your templates would be able to access everything inside the running Ruby VM and write arbitrary Ruby code.

So even if you would adapt the variable binding passed to the template, this wouldn't restrict a malicious user from accessing all your secrets anyway by embedding Ruby into ERB.

If you really want a safe templating language ready to be exposed to users, you should have a look at Liquid (as Stefan said in a comment) or Mustache, both of which aim to provide a safe, non evaluating template environment.

How do you make ruby variables and methods in scope using Thor Templates?

ERB uses ruby's binding object to retrieve the variables that you want. Every object in ruby has a binding, but access to the binding is limited to the object itself, by default. you can work around this, and pass the binding that you wish into your ERB template, by creating a module that exposes an object's binding, like this:

module GetBinding
def get_binding
binding
end
end

Then you need to extend any object that has the vars you want with this module.

something.extend GetBinding

and pass the binding of that object into erb

something.extend GetBinding
some_binding = something.get_binding

erb = ERB.new template
output = erb.result(some_binding)

for a complete example of working with ERB, see this wiki page for one of my projects: https://github.com/derickbailey/Albacore/wiki/Custom-Tasks



Related Topics



Leave a reply



Submit