如何在Rails的Reports控制器中导出Leaderboard数据为CSV?
实现Rails排行榜数据的CSV导出功能
嘿,我来帮你搞定这个CSV导出需求!咱们基于你现有的代码一步步扩展,就能轻松实现导出功能:
第一步:修改控制器,支持CSV响应
首先在现有的leaderboard方法里添加CSV格式支持,让同一个接口既能返回JSON也能返回CSV。更新控制器代码如下:
def leaderboard if params.has_key?(:start_date) && params.has_key?(:end_date) && params.has_key?(:account) # 保留你原有的所有逻辑,用来获取@start_date、@end_date、@conversations、@users等数据 # 新增:根据请求格式返回不同响应 respond_to do |format| format.json # 原有的JSON响应,自动使用leaderboard.json.jbuilder format.csv do # 生成CSV文件并发送给客户端 send_data generate_leaderboard_csv, filename: "leaderboard-#{@start_date.strftime('%Y%m%d')}-#{@end_date.strftime('%Y%m%d')}.csv", type: 'text/csv' end end else render json: {error: 'Invalid parameters'}, status: 422 end end
接着在控制器里添加私有方法generate_leaderboard_csv,复用你在jbuilder里的计算逻辑来构建CSV内容:
private def generate_leaderboard_csv CSV.generate(headers: true) do |csv| # 写入CSV表头,对应JSON里的各个字段 csv << ['User ID', 'User Name', 'Closed Conversations', 'Open Conversations', 'Total Replies', 'Avg Resolution Time', 'Avg First Response Time'] # 遍历每个用户生成行数据 @users.each do |user| closed_count = @conversations.where(user: user).closed.count open_count = @conversations.where(user: user).open.count replies = @conversations.where(user: user).inject(0) do |sum, conversation| sum + conversation.messages.where(updated_at: @start_date..@end_date, direction: 'OUT').count end # 处理空数据场景,避免报错 resolution_times = @conversations.closed.where(user: user).pluck(:resolution_time).compact avg_resolution_time = resolution_times.present? ? formatted_duration(array_mean(resolution_times)) : 'N/A' avg_first_response = Conversation.first_response(@conversations.where(user: user)) || 'N/A' # 未分配用户无ID,用N/A代替 user_id = user.id || 'N/A' csv << [user_id, user.name, closed_count, open_count, replies, avg_resolution_time, avg_first_response] end # 添加总计行,对应JSON里的total_*字段 total_closed = @conversations.closed.count total_open = @conversations.open.count total_replies = @conversations.inject(0) do |sum, conversation| sum + conversation.messages.where(updated_at: @start_date..@end_date, direction: 'OUT').count end csv << ['Total', '', total_closed, total_open, total_replies, '', ''] end end
第二步:添加导出按钮到前端
在你的排行榜页面上添加导出CSV的按钮,带上当前筛选的参数(时间范围、账号等)并指定请求格式为CSV:
<%= link_to 'Export to CSV', reports_leaderboard_path( start_date: params[:start_date], end_date: params[:end_date], account: params[:account], unit: params[:unit], format: :csv ), class: 'btn btn-primary' %>
点击这个按钮,浏览器就会自动下载生成的CSV文件了。
关键细节说明
- 针对你代码里的未分配用户,我特意处理了空ID的情况,用
N/A代替避免CSV出现空值。 - 对平均响应时间、首次响应时间添加了空值判断,无数据时显示
N/A防止报错。 - 文件名用时间范围命名,方便用户区分不同时期的导出文件。
- 确保你现有的
array_mean和formatted_duration方法能返回可序列化的字符串/数字,保证CSV内容正常显示。
这样改完后,就能把截图里的排行榜数据完美导出成CSV啦!
内容的提问来源于stack exchange,提问作者Sista-Night
相关产品推荐
相关产品推荐

