在Rails 3模型中调用实例方法

时间:2011-12-13 01:46:02

标签: ruby-on-rails activerecord csv

我今天开始阅读Rails Antipatterns,我想将其中一些实践付诸实践。我正在重构我最初在控制器中构建的CSV导出。由于这是一个不好的做法,我将其考虑到模型......然后是自己的模型。这样我就可以将该方法重用于其他目的。

我有一个使用以下方法的模型:

#app/models/imagery_request.rb
class ImageryRequest < ActiveRecord::Base

def convert
    ImageryRequestConverter.new(self)
  end

end

我有另一个这样的模型:

#app/models/imagery_request_converter.rb
class ImageryRequestConverter
  attr_reader :imagery_requests

  def initialize(imagery_requests)
    @imagery_requests = imagery_requests
  end

  def to_csv
    csv_string = FasterCSV.generate do |csv|
      # header row
      csv << ["id", "service_name", "description", "first_name", "last_name", "email", "phone_contact", "region",
        "imagery_type", "file_type", "pixel_type", "total_images",
        "tile_size", "progress", "expected_date", "high_priority", "priority_justification",
        "raw_data_location", "service_overviews", "is_def",
        "isc_def", "special_instructions", "navigational_path", "FY Queue",
        "created_at", "updated_at"]
      # data rows
      @imagery_requests.each do |ir|
        csv << [ir.id, ir.service_name, ir.description, ir.first_name, ir.last_name, ir.email,
          ir.phone_contact, ir.region, ir.imagery_type, ir.file_type, ir.pixel_type,
          ir.total_images, ir.tile_size, ir.progress, ir.expected_date, ir.high_priority,
          ir.priority_justification, ir.raw_data_location, ir.service_overviews,
          ir.is_def, ir.isc_def, ir.special_instructions, ir.navigational_path,
          ir.fyqueue, ir.created_at, ir.updated_at
        ]
      end
      # send it to the browser with proper headers
      send_data csv_string,
        :type => 'text/csv; charset=iso-8859-1; header=present',
        :disposition => "attachment; filename=Imagery_Requests-#{Time.now.strftime("%Y%m%d")}.csv"
    end
  end
end

当我尝试在我的视图中引用它时:

<%= link_to @imagery_requests.convert.to_csv %>

我收到错误:

undefined method `convert' for #<ActiveRecord::Relation:0x21f966d0>

如何调用此方法?

2 个答案:

答案 0 :(得分:0)

@imagery_requests变量实际上是一个Relation对象,一旦被调用,它将始终是一个记录集合。您正在调用此对象上的实例方法,因为您在整个集合上调用它而不是此集合中的对象,所以该方法无效。

除此之外,调用link_to中的方法就像你在那里做的那样,不会全力以赴。该链接应转到控制器操作,该操作将解析这些请求并正确返回CSV。

答案 1 :(得分:0)

跟随Ryan Bigg的回答

您有两个问题:

  1. 要调用convert方法,您需要在集合中指定一个对象。例如。 @imagery_requests.first.convert.to_csv@imagery_requests[i].convert.to_csv

  2. 您无法获得文件内容的链接,这是您的代码尝试执行的操作。相反,您需要链接到一个新操作,例如将返回csv的d​​ownload_csv。

  3. 由于新操作(下载文件的csv版本)不是标准restful套件的一部分,因此您需要向资源添加其他操作Eg article

    用户体验(UX)选择: 您可以为ImageryRequests集合的每个成员创建一个下载为csv操作,这意味着想要5个请求的csv版本的人需要下载5个不同的csv文件。

    或者您可以为集合创建下载。但每个http请求都有一个响应。通常的解决方案:使用多个文件将zip文件返回给客户端。

    在任何情况下,您都应该将代码移动到模型中并移出控制器。

    EMail UX解决方案如果创建csv文件花费超过一秒钟,这个特别好 - 因为Rails是单线程的,所有响应应该非常快。

    csv下载的表单应该使用电子邮件地址作为参数,而不是使用文件进行响应。然后使用DelayJob或其他调度程序在后台通过电子邮件发送csv文件。

    您可以将zip文件作为电子邮件附件发送,也可以发送多个csv文件,因为电子邮件可以包含多个附件。

    提示:您的表单应处理多个电子邮件地址,并允许用户在电子邮件中包含封面注释。这将使请求者能够将报告发送给多个人。