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
How to Serve Static Files via Rack
Converting an Array of Objects to Activerecord::Relation
Best Way to Add Comments in Erb
Private Module Methods in Ruby
Ruby - Share Logger Instance Among Module/Classes
Best Ruby on Rails Social Networking Framework
Rails4 Unknown Encoding Name - Cp720
Why Do I Get a "Permission Denied" Error While Installing a Gem
How to Use Rvm and Create Globally Available Gems
What Is the Use of Gemfile in Rails
How to Search a Folder and All of Its Subfolders For Files of a Certain Type
Automatic Counter in Ruby For Each
How to Save a Base64 String as an Image Using Ruby