我发现了一个很棒的railscast,它展示了如何在没有gem的情况下生成XLS,但是可以找到更深入的珍贵文档。 http://railscasts.com/episodes/362-exporting-csv-and-excel?view=asciicast
我被要求创建一个以XLS电子表格形式直接发送到电子邮件的指标列表,但是被告知slug太大而无法添加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。
邮件程序成功生成电子邮件中可见的列表。如何使用邮件程序生成的列表并将其转换为相同电子邮件的XLS附件,同样不使用gem?
Ruby 1.8.7, Rails 3.0.20
答案 0 :(得分:0)
通过抨击墙壁并搜索类似问题找到解决方案来找到解决方案。
我在通知邮件中添加了一个块...
#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") do |format|
format.html { render }
format.xls { attachments["#{login}#{Time.now}.xls"] = @user.to_csv(:col_sep => "\t") }
end
end
通过@user.to_csv
自动创建XLS文件作为附件。我添加了to_csv
方法,该方法基本上是之前的get_factors_and_counts_for_metrics
方法,但已修改。
我必须将代码从示例CSV.generate
更改为FCSV.generate
,并在config / application.rb中添加一些行
#app/models/user.rb
class User < ActiveRecord::Base
...
def to_csv(options = {})
FCSV.generate(options) do |csv|
csv << ["Account Name","Active","Need Updated 8821","% Outstanding","Closed This Month","Total Incorrect"]
ret_factors = []
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|
f_c = f.company
a = f.factor_clients.where(:status => ['a','u']).count
u = f.factor_clients.where("status IN (?) AND (reason_8821 NOT IN (?) OR reason_8821 is ?)",['a'],'current',nil).count
if a == 0 || u == 0
a_u_per = 0
else
a_u_per = ((u.to_f)/(a.to_f) * 100).to_i
end
c = 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
e = f.factor_clients.where(:status => 'e').count
csv << [f_c,a,u,"%#{a_u_per}",c,e]
end
end
end
相应的配置改变..
#config/application.rb
require File.expand_path('../boot', __FILE__)
if RUBY_VERSION < "1.9"
require "rubygems"
require "faster_csv"
#CSV = FCSV
else
require "csv"
end
require 'rails/all'
将mime类型添加到initializers / mime_types.rb:Mime::Type.register "application/xls", :xls
我现在在电子邮件中有XLS附件。