Rails 3:如何回答csv没有模板文件? [英] Rails 3: How to respond_with csv without having a template file?
问题描述
我有一个对象,有一个 to_csv
方法,我想传递给 respond_with
渲染csv从我的控制器。我的代码看起来像这样:
class Admin :: ReportsController< AdminController
respond_to:csv
def trips
respond_with TripReport.new
end
end
TripReport的实例有一个to_csv方法。
我收到以下错误:
ActionView :: MissingTemplate(缺少模板管理/报告/旅行与{:formats = :csv],:handlers => [:erb,:builder,:rjs,:rhtml,:rxml],:locale => [:en,:en]}
所以看起来控制器正在寻找一个模板文件来渲染,我该如何解决?
我宁愿csv格式以类似于json的方式响应,所以它调用对象上的
to_csv
,只是渲染输出,是这可能吗?解决方案我一直在努力完全相同的问题,我可能找到了一个解决方案。
我在阅读Renderers.add源代码时发现了一些线索:json和:xml(link是用于Rails 3.0.10代码,3.1可能已经有一些改变):
https://github.com/rails/rails/blob /v3.0.10/actionpack/lib/action_controller/metal/renderers.rb
首先,添加一个简单的
as_csv
method to your model definition:class Modelname< ActiveRecord :: Base
#...
def as_csv
属性
end
end
这可以是任何东西,只要确保返回一个带有键/值对的哈希。哈希比数组效果更好,因为以后你可以在CSV输出中添加一个标题行。
as_csv
的想法来自Rails的as_json
方法,它返回一个由<$ c $
使用
as_csv
方法,将以下代码放入您的应用程序中的config / initializers
中的文件中(命名为csv_renderer.rb
,例如):require'csv'#将一个.to_csv方法添加到数组实例
类数组
别名old_to_csv to_csv #keep引用原始to_csv方法
def to_csv(options = Hash.new)
#仅当第一个元素实际上具有as_csv方法$ b时才覆盖$ b return old_to_csv(options)unless self.first.respond_to? :as_csv
#使用第一行的键作为标题列
out = first.as_csv.keys.to_csv(options)
self.each {| r | out<< rs.server.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支持:
ModelnamesController< ApplicationController
respond_to:html,:json,:csv
def index
@modelnames = Modelname.all
respond_with(@modelnames)
end
#...
end
代码主要基于:来自Rails源代码的json和:xml行为(见上面的链接)。
目前,
code>哈希传递给块不会传递到
to_csv
调用,因为CSV是相当挑剔的选项,它允许发送。 Rails自身添加了一些默认选项(如:template和其他一些),当将它们传递给to_csv
时,会出现错误。
希望这会有帮助!
。您可以通过向初始化程序添加自己首选的CSV选项来更改默认的CSV呈现行为。I have an object that has a
to_csv
method and I want to pass it torespond_with
to render csv from my controller. My code looks like this:class Admin::ReportsController < AdminController respond_to :csv def trips respond_with TripReport.new end end
Instances of TripReport have a to_csv method.
When I make a request to that action I get the following error:
ActionView::MissingTemplate (Missing template admin/reports/trips with {:formats=>[:csv], :handlers=>[:erb, :builder, :rjs, :rhtml, :rxml], :locale=>[:en, :en]} in view paths
So it looks like the controller is looking for a template file to render. How can I get around this?
I'd rather the csv format responded in a similar way to json, so it calls
to_csv
on the object and just renders the output, is this possible?解决方案I've been struggling with the exact same problem. I might have found a solution.
I found some clues while reading the Renderers.add source code for :json and :xml (link is for Rails 3.0.10 code, 3.1 might have some changes already): https://github.com/rails/rails/blob/v3.0.10/actionpack/lib/action_controller/metal/renderers.rb
First, add a simple
as_csv
method to your model definition:class Modelname < ActiveRecord::Base # ... def as_csv attributes end end
This can be anything, just make sure to return a hash with key/value pairs. A Hash works better than an Array, as with keys you're able to add a header row to the CSV output later on. The idea for
as_csv
comes from Rails'as_json
method, which return a Ruby object that is used byto_json
to generate the actual JSON (text) output.With the
as_csv
method in place, put the following code in a file inconfig/initializers
inside your app (name itcsv_renderer.rb
, for example):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
And finally, add CSV support to your controller code:
class ModelnamesController < ApplicationController respond_to :html, :json, :csv def index @modelnames = Modelname.all respond_with(@modelnames) end # ... end
The initializer code is largely based on the :json and :xml behaviour from the Rails source code (see link above).
Currently, the
options
hash passed to the block doesn't get passed to theto_csv
call, as CSV is quite picky on which options it allows to be sent. Rails adds some default options by itself (like :template and some others), which gives you an error when passing them toto_csv
. You can change the default CSV rendering behaviour by adding your own preferred CSV options to the initializer, of course.Hope this helps!
这篇关于Rails 3:如何回答csv没有模板文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!