Eric Luo
Eric Luo

Reputation: 118

How to attach dynamic file content in email

I want to attach a dynamic file in my email. I have the following code:

attachments["#{@company}likelist.xls"] = File.read("#{Rails.root}/app/views/products/like_list.xls.erb")

like_list.xls.erb is a dynamic HTML table created by iterating a variable in Ruby. I used respond_to format.xls to convert the like_list.html.erb table to XLS, however, the attachment sent is empty as no Ruby code is executed. File.read only reads static files.

like_list.xls.erb looks like this:

<table border="1">
  <thead>
  <tr>
    <th><%= t ('product_table.name')%></th>
    <th><%= t ('product_table.code')%></th>
  </tr>
  </thead>
  <tbody>
    <% @like_list.each do |key, value| %>
      <% value.each do |t| %>
        <tr>
          <td><%=t.code%></td>
          <td><%=key%></td>
...

Is there any way I can attach a dynamic file in Rails 4?

Upvotes: 2

Views: 587

Answers (1)

retgoat
retgoat

Reputation: 2464

I assume that's because you sending just a template. But you should construct a table first.

I don't know what data type is your @like_list is, but let's say it is a Hash.

In that case you should build your attachment. Here is just an example that shows the basic approach:

  # mailer
  def table_deliver
    to = "[email protected]"
    from = "[email protected]"
    subject = "Foo"

    @company = "Ggl"
    @like_list = { foo: 1,
                   bar: 2,
                   baz: 3 }
    attachments["#{@company}likelist.xls"] = build_table(@like_list)
    @body = "Mail body"
    mail(to: to, from: from, subject: subject)
  end

  private

  def build_table(data)
    opts = OpenStruct.new(data)
    template = ERB.new(File.read("#{Rails.root}/app/views/products/like_list.xls.erb"))
    template.result(opts.instance_eval { binding })
  end

# template

<table>
  <thead>
    <th>foo</th>
    <th>bar</th>
  </thead>
  <tbody>
    <% data.each do |k, v| %>
      <tr>
        <td><%= k %></td>
        <td><%= v %></td>
      </tr>
    <% end %>
  </tbody>
</table>

And the result in letter_opener:

email

Attachment opened in libre office

office

Hope that helps and feel free to ask some additional questions.

UPDATE

First you create an OpenStruct from your Hash params. Then create a new ERB class instance.

result is a method of ERB class, that applies params to existing template.

binding is an object that provides access to the instance methods and variables that are owned by another object.

More info here

instance_eval is a Object method that evaluates a string containing Ruby source code, or the given block, within the context of the receiver (obj).

More info here

So, that code do the following

  • creates some struct with key-value pairs
  • creates new template
  • executes binding object in context of template and assigns key-value pairs to the template.

You could refer to this SO post for more details

Upvotes: 1

Related Questions