You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:27:47