listing out available variables in an ERB template

2,011 views
Skip to first unread message

mgerst...@gmail.com

unread,
Sep 26, 2010, 9:07:47 PM9/26/10
to boston-r...@googlegroups.com
Hi Boston Rubiers,

I was hoping someone on the Boston Ruby Group might be able to help me out...

Suppose I have a Ruby ERB template named **my_template.html.erb**, and it contains the following:

    <div><%= @div_1 %></div>
    <div><%= @div_2 %></div>
    <div><%= @div_3 %></div>

Is there a way I can programatically list out all the available variables in the template?

For example, the following method:

    def list_out_variables
      template = File.open("path_to/my_template.html.erb", "rb").read
      erb = ERB.new( template )
      erb.this_method_would_list_out_variables 
    end

would return something like:

    ['div1','div2','div3']


Any help would be greatly appreciated.

Thanks,
Mike

Wyatt Greene

unread,
Sep 26, 2010, 9:11:35 PM9/26/10
to boston-r...@googlegroups.com
Yes, you can.  For which version of Rails?

--
You received this message because you are subscribed to the Boston Ruby Group mailing list
To post to this group, send email to boston-r...@googlegroups.com
To unsubscribe from this group, send email to boston-rubygro...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/boston-rubygroup

mgerst...@gmail.com

unread,
Sep 26, 2010, 11:10:12 PM9/26/10
to boston-r...@googlegroups.com
Rails 3 with Ruby 1.8.7.

Wyatt Greene

unread,
Sep 26, 2010, 11:33:09 PM9/26/10
to boston-r...@googlegroups.com
I'm assuming you're doing this in the context of a normal Rails request and not using ERB in isolation.

If that's the case, you've got a couple of options.  ActiveSupport adds an instance_variable_names method to all objects.  So you can just call it straight in your view like this:

  <%= instance_variable_names.inspect %>

There is also a private method that you can call in your controller like so:

  def index
    @view_assigns = view_assigns
  end

This returns a hash of available variables which you can use in your view:

  <%= @view_assigns.keys.inspect %>

In either case you'd have to filter out some standard variables that Rails throws in there.

Hope this helps,
Wyatt

mgerst...@gmail.com

unread,
Sep 27, 2010, 7:29:55 AM9/27/10
to boston-r...@googlegroups.com
Thanks Wyatt, but I'm actually doing this outside of a normal rails request. I'm thinking now to just read in the template file, convert it to a string and then use regex to find all the instance variables using something like
var_array = template.scan(/(\@[a-z]+[0-9a-z]*)/i).uniq


Alex Rothenberg

unread,
Sep 27, 2010, 9:27:39 AM9/27/10
to Boston Ruby Group
I think you can use the instance_variables method Ruby's Object (see
http://ruby-doc.org/core/classes/Object.html#M000366) and then you
wouldn't depend on Rails.

Something like:

<%= instance_variables %>

This would give you all the instance variable that are defined but it
looks like you may want to list all the instance variables your erb
file uses and this wont help for that.

Hope this helps
Alex




On Sep 27, 7:29 am, "mgerstenbl...@gmail.com"
<mgerstenbl...@gmail.com> wrote:
> Thanks Wyatt, but I'm actually doing this outside of a normal rails request.
> I'm thinking now to just read in the template file, convert it to a string
> and then use regex to find all the instance variables using something like
>
> var_array = template.scan(/(\@[a-z]+[0-9a-z]*)/i).uniq
>
> On Sun, Sep 26, 2010 at 11:33 PM, Wyatt Greene <techifer...@gmail.com>wrote:
>
>
>
> > I'm assuming you're doing this in the context of a normal Rails request and
> > not using ERB in isolation.
>
> > If that's the case, you've got a couple of options.  ActiveSupport adds an
> > instance_variable_names method to all objects.  So you can just call it
> > straight in your view like this:
>
> >   <%= instance_variable_names.inspect %>
>
> > There is also a private method that you can call in your controller like
> > so:
>
> >   def index
> >     @view_assigns = view_assigns
> >   end
>
> > This returns a hash of available variables which you can use in your view:
>
> >   <%= @view_assigns.keys.inspect %>
>
> > In either case you'd have to filter out some standard variables that Rails
> > throws in there.
>
> > Hope this helps,
> > Wyatt
>
> > On Sep 26, 2010, at 11:10 PM, mgerstenbl...@gmail.com wrote:
>
> > Rails 3 with Ruby 1.8.7.
>
> > On Sun, Sep 26, 2010 at 9:11 PM, Wyatt Greene <techifer...@gmail.com>wrote:
>
> >> Yes, you can.  For which version of Rails?
>

Wyatt Greene

unread,
Sep 27, 2010, 9:56:05 AM9/27/10
to boston-r...@googlegroups.com
Hi Mike,

I think Alex's suggestion is the best you could come up with.

Why do you want to list the available instance variables?

--Wyatt

mgerst...@gmail.com

unread,
Sep 27, 2010, 12:57:28 PM9/27/10
to boston-r...@googlegroups.com
Thanks for your help Wyatt and Alex. I ended up writing the following class

class Template
  attr_accessor :file_path,:contents

  def self.all
    Dir.glob("lib/templates/*").collect{|t| Template.new(t)}
  end 
 
  def initialize(file_path)
    @file_path = file_path
    @contents = File.open(@file_path, "rb").read
  end 
 
  def variables
    self.contents.scan(/(\@[a-z]+[0-9a-z_]*)/i).uniq
  end 
end

The variables method returns an array of all a template's instance variables (as strings).

As to why I want to list the available instance variables, it'll make more sense within the larger context of what I'm trying to do:

I'm building an interface where users select a template, and then fills in a form with fields that are based on the template's instance variables. For example, using the template:


    <div><%= @div_1 %></div>
    <div><%= @div_2 %></div>
    <div><%= @div_3 %></div>

The user would be presented with a form containing something like:

<%= text_area_tag :div_1 %>
<%= text_area_tag :div_2 %>
<%= text_area_tag :div_3 %>

Upon submission, I'll save the data as as serialized string. At a later point, I'll convert the saved data to instance variables and render the ERB template.

I haven't thought this through all the way yet, but please let me know if you see any potential snags.

Alex Rothenberg

unread,
Sep 27, 2010, 1:43:59 PM9/27/10
to Boston Ruby Group
You may run into trouble with more complicated erb files where the
instance variables are objects other than strings. I can imagine

<div><%= @person.first_name %></div>
<div><%= @person.last_name %></div>

You'll need to create a form that instantiates the first and last
names of a person which I'm sure you can. But, I'm not sure how you'd
handle it if you had 3rd line

<div><%= @person.full_name %></div>

where you expected the full_name to be "#{first_name} #{last_name}".

Thanks
Alex

On Sep 27, 12:57 pm, "mgerstenbl...@gmail.com"

Ben Tucker

unread,
Sep 27, 2010, 2:34:55 PM9/27/10
to Boston Ruby Group
Also, if you happen to have any email addresses (for example) in your
templates they're going to come through as if they are instance
variables.

Given what you're trying to do, I'm wondering if using instance
variables really makes sense? Why not some more specialized
"placeholder" syntax? Something like #DIV_1#, #DIV_2#, etc which you
could easily replace with a regular expression? Or if you don't want
to do your own parsing, perhaps you could use a little method_missing?
magic allowing for: <%= div_1 %>

-Ben

Wyatt Greene

unread,
Sep 27, 2010, 5:47:10 PM9/27/10
to boston-r...@googlegroups.com
And twitter names. :)

The current approach of thinking in terms of instance variables won't work well here (consider how hard it would be to debug errors, for example). Ruby offers so many tools: objects, procs, DSLs, etc. that I'm sure there's an elegant Ruby way to handle what you're trying to do. I'd love to offer some suggestions but it's not clear to me what the ultimate problem is (for example, the users you mention...are they Ruby programmers or someone sitting on the other side of a browser?). I can understand if you don't feel like describing the problem in full here. Regardless, it's almost certainly desirable to define your own abstraction rather than trying to guess based on what instance variables are defined.

mgerst...@gmail.com

unread,
Sep 28, 2010, 12:49:25 PM9/28/10
to boston-r...@googlegroups.com
You guys are absolutely right, using "instance variables" is not the best way to go about this; using a specified placeholder syntax and replacing it with regex is the better approach.

Thanks for all your suggestions everyone!

Pascal Rettig

unread,
Sep 28, 2010, 1:30:01 PM9/28/10
to boston-r...@googlegroups.com
If you're not completely bound to erb templates - I'm not sure what
exactly the use case is, but have you considered using one of the other
templating languages - by the time you are doing regex replaces you sort
of leaning into that territory already. (something like
http://github.com/jlong/radius )

I know radius lets you define a tag_missing method that you could use to
capture missing tags

Some other options include:
http://github.com/defunkt/mustache
http://www.liquidmarkup.org/


-Pascal

Dmitry

unread,
Sep 29, 2010, 9:32:00 PM9/29/10
to boston-r...@googlegroups.com
As rails 3.0.0 came out and ruby 1.9.2 is more or less stable, has anyone tried to run it in prod on nginx/passenger?


I'm trying rails 3.0.0. and ruby 1.9.2 via rvm with nginx-0.8.35 and passenger 2.2.15. At first things work fast, but as more request start to come in, the instance would start to choke. There would be ruby process taking 50% of CPU and it would take up to few minutes to fulfill a simple request which would normally take few ms.
Prior to this everything was working reasonably well with rails 3 and ree and the same versions of nginx and passenger. The last thing that I did which threw it off was switching to ruby 1.9.2.

Has anyone had a success running this or similar setup in prod?

Any help or suggestion would be greatly appreciated since I'm running out of options at this point and really need to get it figure out rather soon.


Dmitry

Wyatt Greene

unread,
Sep 29, 2010, 9:46:55 PM9/29/10
to boston-r...@googlegroups.com
I haven't tried this stack yet; I've been running Rails 3 + 1.8.7 on Heroku.

You could use strace to try to figure out why the Ruby process is hanging:


You can also try interacting with the hung Ruby process to figure out what's going on.  I haven't done that yet but some people have:



Wyatt Greene

unread,
Sep 29, 2010, 9:53:05 PM9/29/10
to boston-r...@googlegroups.com
This guy is using Passenger 3.  Might want to give that a try.  http://twitter.com/#!/jschwindt/statuses/25744032792

On Sep 29, 2010, at 9:32 PM, Dmitry wrote:

Dmitry

unread,
Sep 29, 2010, 9:54:18 PM9/29/10
to boston-r...@googlegroups.com
Thanks Wyatt, 
will definitely give it a try,

btw, forgot to mention (if that would make a difference), I'm deploying it on Ubuntu 10 amazon instance

Dmitry

unread,
Sep 29, 2010, 9:55:42 PM9/29/10
to boston-r...@googlegroups.com
I was hesitant to run the passenger 3 since it's not at a prod level yet, I guess at this point will have to consider that as an option since I have nothing to loose.

Girish Tryambake

unread,
Sep 29, 2010, 10:53:41 PM9/29/10
to boston-r...@googlegroups.com
with your configuration rvm is not a good options. some how it was giving me some problem too.
if possible try using ruby 1.9.2 as system 

Dmitry

unread,
Sep 30, 2010, 6:54:40 AM9/30/10
to boston-r...@googlegroups.com
I was suspecting that, though was still trying to benefit from the rvm convenience, will have to try your suggestion and will let you know if it worked, 
than you

Dmitry Amelchenko

unread,
Sep 30, 2010, 5:46:46 PM9/30/10
to boston-r...@googlegroups.com
I started using the passenger3.pre and it seems to have solved the problem -- everything is superfast now and I can use ruby 1.9.2 via rvm. Though the static images stopped rendering now, looking into it...

Thanks everyone for the suggestions.

Reply all
Reply to author
Forward
0 new messages