2011-12-13 46 views
0

我今天開始閱讀Rails Antipatterns,並希望將其中一些實踐付諸實踐。我正在重構最初內置在控制器中的CSV導出。由於這是一個不好的做法,我把它分解成模型......然後是它自己的模型。這樣我可以將該方法用於其他目的。在Rails 3模型中調用實例方法

我有下面的方法模型:

#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> 

如何調用此方法?

回答

0

@imagery_requests變量實際上是一個Relation對象,它一旦被調用就會始終是記錄的集合。您正在對此對象調用實例方法,因爲您在整個集合上調用該方法,而不是此集合中的對象,所以無法工作。

除此之外,調用link_to中的方法,就像你在那裏做的一樣,不會全部工作。該鏈接應轉到控制器操作,該操作解析這些請求並正確返回CSV。

+0

所以我基本上必須把所有CSV創建代碼放在控制器動作中?必須有更優雅/可重用的方式。 –

0

後續瑞恩比格的回答

你有兩個問題:

  1. 要調用轉換方法,你需要指定集合中的對象。例如。 @imagery_requests.first.convert.to_csv@imagery_requests[i].convert.to_csv

  2. 您不能鏈接到文件的內容,這是您的代碼正在嘗試執行的操作。相反,您需要鏈接到一個新的操作,例如download_csv,它將返回csv。

由於新的動作(下載文件的CSV版本)是不標準的REST風格的套件的一部分,你需要添加額外行動的資源。 Eg article

用戶體驗(UX)的選擇: 您可以創建一個下載作爲ImageryRequests集合的每個成員 CSV作用,這將意味着誰想要CSV版本5條的要求將需要一個人下載5個不同的csv文件。

或者您可以爲集合創建下載。但是每個http請求都有一個響應。通常的解決方案:使用多個文件將一個zip文件返回給客戶端。

在任何情況下,您都應該將代碼移入模型並移出控制器。

EMail UX解決方案如果創建csv文件需要一秒多的時間,這個特別好,因爲Rails是單線程的,所有響應都應該非常快。

csv下載的表單應該將電子郵件地址作爲參數,而不是使用文件進行響應。然後使用DelayJob或其他調度程序在後臺通過電子郵件發送csv文件。

由於電子郵件可能有多個附件,您可以將該zip文件作爲電子郵件附件發送或發送多個csv文件。

提示:您的表單應處理多個電子郵件地址,並允許用戶在電子郵件中包含封面註釋。這將使請求者能夠將報告發送給多個人。

+0

對,我瞭解有關link_to的查看問題。就我的用戶體驗而言,我希望所有行都能以一個CSV文件返回。將來,我將會有一個高級搜索,它會根據日期範圍返回一個CSV。 –

相關問題