简体   繁体   English

干燥Rails控制器代码以进行数据导出

[英]drying up rails controller code for data export

Not sure if this is an appropriate question so forgive me. 不知道这是否是一个适当的问题,请原谅。

I have the following code in a controller action 我在控制器操作中有以下代码

unless @users.empty?
  book = Spreadsheet::Workbook.new
  sheet1 = book.create_worksheet :name => 'export'
  sheet1.row(0).concat ["Label1", "Label2", "Label3"]
  @users.each_with_index do |e, i|
    sheet1.row(i+1).concat([e.field1, e.field2, e.field3])
  end
  require 'stringio'
  data = StringIO.new ''
  book.write data
  send_data data.string, :type=>"application/excel", :disposition=>'attachment', :filename => "export_#{l(Date.today)}.xls"
end

This allows me to have a button on a form that runs an export. 这使我可以在运行导出的表单上有一个按钮。 Whilst this is very useful, I am using this code all over the place. 尽管这非常有用,但我在各处都使用此代码。 In fact, I have 19 instances of this code across various controllers in the app. 实际上,我在应用程序的各个控制器上有19个此代码实例。 Is there a way I can move this code to another file, and pass into it a hash of the labels and fields so that I only have to maintain one instance of the export code? 有没有一种方法可以将这段代码移到另一个文件,然后将标签和字段的哈希值传递给它,这样我只需要维护导出代码的一个实例?

thanks 谢谢

Basic of MVC is to have as much as skinnier controllers, and your case is perfect example, to prevent to repeat your code. MVC基础是拥有尽可能多的瘦控制器,您的案例就是一个很好的例子,可以防止重复代码。

Solution for this is to move your code to models the M in the MVC pattern, it is responsible for all the business logic. 解决方案,这是对你的代码移到modelsMMVC模式,它负责所有的业务逻辑。

Move this method to the module . 将此方法移至module In app/models/concers/ folder create new file sheetable.rb app/models/concers/文件夹中创建新文件sheetable.rb

require 'active_support/concern'

module Sheetable
  extend ActiveSupport::Concern

  module ClassMethods    
    def new_sheet objects
      unless objects.empty?
        book = Spreadsheet::Workbook.new
        sheet1 = book.create_worksheet :name => 'export'
        sheet1.row(0).concat ["Label1", "Label2", "Label3"]
        objects.each_with_index do |e, i|
          sheet1.row(i+1).concat([e.field1, e.field2, e.field3])
        end
        require 'stringio'
        data = StringIO.new ''
        book.write data    
      end
    end
  end
end

Now include module in your model and it will have class method new_sheet . 现在在model包含module ,它将具有类method new_sheet

class User < ActiveRecord::Base
  ...
  include Sheetable
  ...
end

or in other model 或其他型号

class OtherModel < ActiveRecord::Base
  ...
  include Sheetable
  ...
end

To use this 要使用这个

data = User.new_sheet(@users) # or OtherModel.new_sheet(@other_models)
if data
 send_data data.string, :type=>"application/excel", :disposition=>'attachment', :filename => "export_#{l(Date.today)}.xls"
end

Now you have moved the logic to the model next step is to refactor this method, make it more simpler. 现在您已将逻辑移至model下一步是重构此方法,使其更简单。

I'd begin with moving the code to where the responsibility belongs. 我将从将代码移到职责所属的地方开始。 It seems that you're exporting data of a certain set of users to a spreadsheet. 似乎您正在将一组特定用户的数据导出到电子表格。 So I'd move the code to the User class, eg 所以我将代码移到User类,例如

def self.export_subset_to_spreadsheet(users)
  ... your code ...
end

and then call it from your controller with User.export_subset_to_spreadsheet(@users) . 然后使用User.export_subset_to_spreadsheet(@users)从您的控制器中调用它。

This is step one. 这是第一步。 You can certainly take it further from there, but at least this allows you to get rid of the most pressing problem: the 19 duplications of that whole block of code. 您当然可以从那里走得更远,但是至少这可以使您摆脱最紧迫的问题:整个代码块的19个重复项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM