【发布时间】:2014-04-18 16:46:55
【问题描述】:
我发现了一个很棒的 railscast,它展示了如何在没有 gem 的情况下生成 XLS,但可以找到更深入的珍贵小文档。 http://railscasts.com/episodes/362-exporting-csv-and-excel?view=asciicast
有人要求我创建一个以 XLS 电子表格形式直接发送至电子邮件的指标列表,但我被告知该信息量太大而无法添加 gem。
耙子任务:
#scheduler.rake
namespace :scheduler do
...
desc "Email client metrics - 100pm every Sunday"
task :email_client_metrics => :environment do
# run every Sunday
Notifications.send_metrics_email('name1@company.com').deliver
Notifications.send_metrics_email('name2@company.com').deliver
end
任务调用通知邮件程序:
#app/mailers/notifications.rb
class Notifications < ActionMailer::Base
...
def send_metrics_email(email_addr)
@email = email_addr
#rather than splitting on @, we are looking for a specific name to avoid mistakes.
if @email =~ /name1/
login = "name1"
elsif @email =~ /name2/
login = "name2"
end
@user = User.find_by_login(login)
@factor_clients,@active_count,@update_count,@closed_per_month,@incorrect = @user.get_factors_and_counts_for_metrics
mail(:to => @email, :subject => "Weekly Client Metrics")
end
邮件程序调用用户模型中的方法:
#user.rb
class User < ActiveRecord::Base
...
def get_factors_and_counts_for_metrics()
ret_factors,ret_actives,ret_updates,ret_cls_per_mo,ret_incorrect = [],[],[],[],[]
factors.includes(:factor_clients).where(:status => "a").find_each { |f| ret_factors << f }
ret_factors = ret_factors.sort_by { |f| f.company }
ret_factors.each do |f|
ret_actives << f.factor_clients.where(:status => ['a','u']).count
ret_updates << f.factor_clients.where("status IN (?) AND (reason_8821 NOT IN (?) OR reason_8821 is ?)",['a'],'current',nil).count
ret_cls_per_mo << f.factor_clients.joins(:client_status_changes).where("factor_clients.status IN (?) AND client_status_changes.change_type IN (?) AND client_status_changes.change_time BETWEEN (?) AND (?)", ['c'],['a2c','r2c','ia2c','e2c','u2c','o2c'],Time.now.beginning_of_month,Time.now.end_of_month).count
ret_incorrect << f.factor_clients.where(:status => 'e').count
end
return [ret_factors,ret_actives,ret_updates,ret_cls_per_mo,ret_incorrect]
end
当然,所有这些都会呈现邮件模板:
<div>
Hello <%= @user.first_name %>,<br />
<p>
Here is the breakdown of your client metrics.
</p>
</div>
<p>
<div>
<table style="font-size: 12; margin-right: auto; margin-left: auto; width: 90%;"border=1 cellpadding=2 cellspacing=0>
<tr>
<th style="background: #8B8B8B; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#1E78CC, endColorstr=#0C89E6); background: -webkit-gradient(linear, left top, left bottom, from(#1E78CC), to(#0C89E6)); background: -moz-linear-gradient(top, #1E78CC, #0C89E6);">Account Name</th>
<th style="background: #8B8B8B; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#1E78CC, endColorstr=#0C89E6); background: -webkit-gradient(linear, left top, left bottom, from(#1E78CC), to(#0C89E6)); background: -moz-linear-gradient(top, #1E78CC, #0C89E6);">Active</th>
<th style="background: #8B8B8B; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#1E78CC, endColorstr=#0C89E6); background: -webkit-gradient(linear, left top, left bottom, from(#1E78CC), to(#0C89E6)); background: -moz-linear-gradient(top, #1E78CC, #0C89E6);">Need Updated 8821</th>
<th style="background: #8B8B8B; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#1E78CC, endColorstr=#0C89E6); background: -webkit-gradient(linear, left top, left bottom, from(#1E78CC), to(#0C89E6)); background: -moz-linear-gradient(top, #1E78CC, #0C89E6);">% Outstanding</th>
<th style="background: #8B8B8B; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#1E78CC, endColorstr=#0C89E6); background: -webkit-gradient(linear, left top, left bottom, from(#1E78CC), to(#0C89E6)); background: -moz-linear-gradient(top, #1E78CC, #0C89E6);">Closed This Month</th>
<th style="background: #8B8B8B; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#1E78CC, endColorstr=#0C89E6); background: -webkit-gradient(linear, left top, left bottom, from(#1E78CC), to(#0C89E6)); background: -moz-linear-gradient(top, #1E78CC, #0C89E6);">Total Incorrect</th>
</tr>
<% shade = "dark" %>
<% @factor_clients.zip(@active_count,@update_count,@closed_per_month,@incorrect).each do |f,a,u,c,i| %>
<% if shade == "background: #dddddd;"
shade = "background: #ffffff;"
else
shade = "background: #dddddd;"
end %>
<tr style="<%= shade %>">
<% if f %>
<td><%= f.company %></td>
<td><%= a %></td>
<td><%= u %></td>
<td><% if a == 0 || u == 0 then %><%= 0 %><% else %><%= ((u.to_f)/(a.to_f) * 100).to_i %><% end %> %</td>
<td><%= c %></td>
<td><%= i %></td>
<% end %>
</tr>
<% end %>
<% if @active_count.any? && @update_count.any? %>
<tr>
<th style="background: #8B8B8B; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#1E78CC, endColorstr=#0C89E6); background: -webkit-gradient(linear, left top, left bottom, from(#1E78CC), to(#0C89E6)); background: -moz-linear-gradient(top, #1E78CC, #0C89E6);">SUM</th>
<th style="background: #8B8B8B; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#1E78CC, endColorstr=#0C89E6); background: -webkit-gradient(linear, left top, left bottom, from(#1E78CC), to(#0C89E6)); background: -moz-linear-gradient(top, #1E78CC, #0C89E6);"><%= @active_count.sum %></th>
<th style="background: #8B8B8B; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#1E78CC, endColorstr=#0C89E6); background: -webkit-gradient(linear, left top, left bottom, from(#1E78CC), to(#0C89E6)); background: -moz-linear-gradient(top, #1E78CC, #0C89E6);"><%= @update_count.sum %></th>
<th style="background: #8B8B8B; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#1E78CC, endColorstr=#0C89E6); background: -webkit-gradient(linear, left top, left bottom, from(#1E78CC), to(#0C89E6)); background: -moz-linear-gradient(top, #1E78CC, #0C89E6);"><%= (((@update_count.sum.to_f)/(@active_count.sum.to_f)) * 100).to_i %> %</th>
<th style="background: #8B8B8B; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#1E78CC, endColorstr=#0C89E6); background: -webkit-gradient(linear, left top, left bottom, from(#1E78CC), to(#0C89E6)); background: -moz-linear-gradient(top, #1E78CC, #0C89E6);"><%= @closed_per_month.sum %></th>
<th style="background: #8B8B8B; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#1E78CC, endColorstr=#0C89E6); background: -webkit-gradient(linear, left top, left bottom, from(#1E78CC), to(#0C89E6)); background: -moz-linear-gradient(top, #1E78CC, #0C89E6);"><%= @incorrect.sum %></th>
</tr>
<% end %>
</table>
</div>
</p>
我相信棘手的部分是必要的信息从各种包含和连接查询汇集在一起,所有这些都与用户模型分开启动,并通过 zip() 组合在一起 - 所以我没有立即看到一种方法说@variable.to_xls。此外,电子邮件是通过 rake 任务生成的,所以我无法弄清楚如何/在何处/何时为附件生成 XLS。
邮件程序成功生成了一个在电子邮件中可见的列表。如何在不使用 gem 的情况下再次将邮件生成的列表转换为同一电子邮件的 XLS 附件?
红宝石 1.8.7, Rails 3.0.20
【问题讨论】:
-
您可以将其作为
csv发送,Excel 可以轻松打开,用户可以从那里另存为xls。xls是 Microsoft 专有的二进制格式,如果你真的想要,你可以尝试为xlsx编写自己的编译器,它使用开放的 xml,但如果没有 gem,那会很麻烦。您的另一个选择是在模型或猴子补丁 to_xls 中创建这个zipped对象到它返回的任何类中。如果您有一些代码,它将产生更好的响应。包括对象的构建和期望。 -
为澄清添加了代码。
标签: ruby-on-rails ruby xls