Search code examples
ruby-on-railsrubyruby-on-rails-3eval

How to execute view code stored in string in run time with eval in Rails 3.2 erb?


What we are trying to do is to store a chunk of erb code in a string and then execute the code in run time. Here is a test we did :

  1. take out a chunk of the code from a working erb file and,
  2. rewrite the erb file with eval.

Here is the chunk of erb code taken out:

<tr>
      <th>#</th>
      <th><%= t('Date') %></th>
      <th><%= t('Project Name') %></th>
      <th><%= t('Task Name') %></th>
      <th><%= t('Log') %></th>
      <th><%= t('Entered By') %></th>
  
    </tr>

    <% @logs.each do |r| %>
        <tr>
          <td><%= r.id %></td>
          <td><%= (r.created_at + 8.hours).strftime("%Y/%m/%d")%></td>
          <td><%= prt(r, 'task.project.name') %></td>
          <td><%= prt(r, 'task.task_template.task_definition.name') %></td>
          <td><%= prt(r, :log) %></td>
          <td><%= prt(r, 'last_updated_by.name') %></td>
          
        </tr>
    <% end %>

t() is the translation method for internationalization.

Here is the erb file after rewriting:

  <table class="table table-striped">
    <% code = find_config_const('task_log_view', 'projectx')%>
    <%= eval(code)%>

  </table>

Before rewriting, the chunk of code goes between <table>. Now variable code returns a string of the chunk of code and eval execute the chunk of code. But here is the error:

(eval):1: syntax error, unexpected '<'
(eval):4: syntax error, unexpected tIDENTIFIER, expecting $end
      <th><%= t('Project Name') %></th>
               ^

Extracted source (around line #6):

4:   <table class="table table-striped">
5:      <% code = find_config_const('task_log_view', 'projectx')%>
6:     <%= eval(code)%>
7: 
8:   </table>
9: 

What's wrong with the code above?


Solution

  • eval works by evaluating ruby code.

    irb(main):001:0> eval('puts "Hello World"')
    Hello World
    => nil
    

    while Converting erb template should be done with ERB class

    irb(main):002:0> require 'erb'
    irb(main):003:0> ERB.new('<%= "Hello World" %>').result
    => "Hello World"
    

    My guess is that the code is actually a string that contain ERB template rather than ruby code.

    Nonetheless I don't think that this is a good approach. task.project.name are probably from database that possibly came from user input. doing eval on that seems not like a good idea.

    Probably you could solve your problem with normal partials