我一直在努力解决完全相同的问题。我可能已经找到了解决方案。
我在阅读 :json 和 :xml 的 Renderers.add 源代码时发现了一些线索(链接是 Rails 3.0.10 代码,3.1 可能已经有一些变化):
https://github.com/rails/rails/blob/v3.0.10/actionpack/lib/action_controller/metal/renderers.rb
首先,在模型定义中添加一个简单的as_csv 方法:
class Modelname < ActiveRecord::Base
# ...
def as_csv
attributes
end
end
这可以是任何东西,只要确保返回带有键/值对的散列即可。 Hash 比 Array 更有效,因为您可以稍后将标题行添加到 CSV 输出中。 as_csv 的想法来自 Rails 的 as_json 方法,该方法返回一个 Ruby 对象,to_json 使用该对象来生成实际的 JSON(文本)输出。
使用as_csv 方法,将以下代码放入您应用内config/initializers 的文件中(例如,将其命名为csv_renderer.rb):
require 'csv' # adds a .to_csv method to Array instances
class Array
alias old_to_csv to_csv #keep reference to original to_csv method
def to_csv(options = Hash.new)
# override only if first element actually has as_csv method
return old_to_csv(options) unless self.first.respond_to? :as_csv
# use keys from first row as header columns
out = first.as_csv.keys.to_csv(options)
self.each { |r| out << r.as_csv.values.to_csv(options) }
out
end
end
ActionController::Renderers.add :csv do |csv, options|
csv = csv.respond_to?(:to_csv) ? csv.to_csv() : csv
self.content_type ||= Mime::CSV
self.response_body = csv
end
最后,为您的控制器代码添加 CSV 支持:
class ModelnamesController < ApplicationController
respond_to :html, :json, :csv
def index
@modelnames = Modelname.all
respond_with(@modelnames)
end
# ...
end
初始化代码主要基于 Rails 源代码中的 :json 和 :xml 行为(参见上面的链接)。
目前,传递给块的 options 哈希不会传递给 to_csv 调用,因为 CSV 对允许发送哪些选项非常挑剔。 Rails 自己添加了一些默认选项(例如 :template 和其他一些选项),当您将它们传递给 to_csv 时会出现错误。当然,您可以通过将自己喜欢的 CSV 选项添加到初始化程序来更改默认的 CSV 呈现行为。
希望这会有所帮助!