Rails 3:如何回答csv没有模板文件? [英] Rails 3: How to respond_with csv without having a template file?

查看:146
本文介绍了Rails 3:如何回答csv没有模板文件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个对象,有一个 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 to respond_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 by to_json to generate the actual JSON (text) output.

With the as_csv method in place, put the following code in a file in config/initializers inside your app (name it csv_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 the to_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 to to_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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆