2

I'm displaying duplicate blocks of content in an erb (email template) and I thought I would make a simple class that would represent each block.

I tried something like this which works if I manually render the erb, but if I try to send the email I throw.

<%
class EmailBox
  attr_accessor :text, :textLink,
end
x = EmailBox.new
x.textLink = 'https://www.google.com/' 
x.text = 'blah'
@boxes = []
@boxes.push x
%>

<% @boxes.each do |row| %>
         <a style="text-decoration:none;color:#666;" href="<%=row.textLink%>"><%=row.text%></a>
<% end %>

The error I'm getting is:

/Users/x/appname/app/views/clip_mailer/send_clip_with_destination.html.erb:205: class definition in method body
/usr/local/rvm/gems/ruby-1.9.3-p392/gems/actionpack-3.2.13/lib/action_view/template.rb:297:in `module_eval'
/usr/local/rvm/gems/ruby-1.9.3-p392/gems/actionpack-3.2.13/lib/action_view/template.rb:297:in `compile'
/usr/local/rvm/gems/ruby-1.9.3-p392/gems/actionpack-3.2.13/lib/action_view/template.rb:244:in `block in compile!'
<internal:prelude>:10:in `synchronize'
/usr/local/rvm/gems/ruby-1.9.3-p392/gems/actionpack-3.2.13/lib/action_view/template.rb:232:in `compile!'

I'm repeating myself, but this works just fine when I manually render the template by opening it on disk and running ERB.new(file).result(binding)

benathon
  • 7,455
  • 2
  • 41
  • 70
  • Why don't you put class declaration into model and all the filling stuff into controller? – Yevgeniy Anfilofyev Jun 03 '13 at 11:09
  • I'm just using this simple class one time to build the body of the email. it's not relevant for anything else. I'm also not looping through database records or anything, I'm manually building these repeating blocks. – benathon Jun 03 '13 at 19:48
  • 1
    Placing class into models doesn't mean you use database, it could be just class (model). This and the logic in controller is a convention and it's important. :) – Yevgeniy Anfilofyev Jun 04 '13 at 03:49
  • It's not exactly a model. It's more like a shorthand for a block of html. I also looked into partials but I decided they weren't right for the job – benathon Jun 04 '13 at 04:45

2 Answers2

1

You can't, as far as I'm aware, define classes within erb. Even if you could, I'd question the design logic behind such an approach - in general you want to keep a wall of separation between your data and templates.

All of that said, you can accomplish something similar with a method which returns a list or hash, etc:

<% def get_data; return {:text => 'blah', :textLink => 'http://www.google.com'}; end %>
<%= get_data[:textLink] %>
dliggat
  • 418
  • 1
  • 4
  • 7
  • I like your solution but it means I have to type an extra [:] for every fetch. I'm too lazy for that. Typical rubyist no? – benathon Jun 06 '13 at 08:53
  • 1
    Rubyists who don't like typing colons aren't long for this world ;) The OpenStruct solution is a closer mapping to your stated requirements anyway, so glad that worked out. – dliggat Jun 06 '13 at 13:47
  • I wish the guy who commented had left his answer. I am seriously lucky that SO sent me the email. no point for him tho I guess. – benathon Jun 06 '13 at 20:53
0

Somebody answered " If you really want to define a class inside the template you could use a Struct..." and then deleted it. I don't know who but I got an email saying as much. Anyways this lead me down a path of structs, and eventually I found OpenStruct. The conversion is very simple and takes fewer lines:

<%
x = OpenStruct.new
x.textLink = 'https://www.google.com/' 
x.text = 'blah'
@boxes = []
@boxes.push x
%>

<% @boxes.each do |row| %>
         <a style="text-decoration:none;color:#666;" href="<%=row.textLink%>"><%=row.text%></a>
<% end %>
benathon
  • 7,455
  • 2
  • 41
  • 70