我有一个对象Foo
。 Foo
有一个控制器,控制器有一个标准索引,可以显示包含每个Foo
属性的表中的所有Foo
,并允许用户对Foo
进行过滤和排序1}}由这些属性。这部分只是花花公子。
class FoosController < ApplicationController
def index
@foos = Foo.filter_data_by_params
@foos = Foo.sort_some_data_by_params
respond_to do |format|
format.html { standard_index } # Has link to format xls
format.xls do
require_relative '../path/to/spreadsheet_view.rb' # Uh oh.
create_spreadsheet # method in spreadsheet_view that generates and returns xls file
end
end
end
end
但另一部分对我来说似乎很危险。索引视图还为用户提供了将收集的索引数据视为电子表格的选项。但是,因为尝试使用XLS ERB返回XML 2004文件而不是与我们公司的工作流程兼容的97-2004文件,所以我必须调用使用Spreadsheet gem的常规.rb
文件来生成97-2004兼容的电子表格而不是.erb
文件。
def create_spreadsheet
book = Spreadsheet::Workbook.new
sheet = book.create_worksheet(:name => 'Sheet1')
fields = Foo.columns
sheet.row(0).concat(fields)
@foos.each_with_index do |foo, index|
fields.each do |field|
sheet.row(index + 1).push foo.field
end
end
spreadsheet = StringIO.new
book.write spreadsheet
send_data spreadsheet.string, :filename => "foos.xls", :type => "application/vnd.ms-excel"
end
现在,我不确定使用外部.rb
文件而不是.erb
文件本身是如此糟糕,但我确实认识到require_relative
这可能是一种可怕的方式。
如果我错了,请纠正我,但根据我的理解,require_relative
每个Rails会话只能使用一次(与任何Ruby require
一样),并定义&#34 ;创建电子表格&#34;关于整个应用程序范围的方法,而不仅仅是我使用FoosController
的当前实例。
tl;博士:我需要的是一种向FoosController#index
公开方法的方法,该方法可以使用@foos
填充的index
变量来生成电子表格,就像查看文件一样会不会搞砸其他所有东西 - 也就是说,它可以在不重新加载服务器的情况下进行编辑,并且不会污染我应用程序的其余部分。
答案 0 :(得分:0)
通常在Rails 4中用Concerns处理。你可以通过声明一个模块并使用它来在Rails 3中实现类似的效果:
module SpreadsheetCreator
def create_spreadsheet
# ...
end
end
只要将其命名为spreadsheet_creator.rb
且位于ActiveSupport自动加载器可以找到的路径中,您就不需要做任何特殊的事情来包含它。 app/helpers
或app/models
应该是其中一个,即使它不够理想。对于像这样的非模型非控制器助手,Rails 4有一个concerns
位置。
然后在另一个背景下:
class FoosController < ApplicationController
include SpreadsheetCreator
end
这是一个非常草率的设计,因为你的创造者真的很想进入控制器并对控制器的结构做出很多假设。例如,@foos
没有明确的依赖关系,它只是神奇地传播。在单独的实现文件之间共享这样的实例变量会使对代码的理解变得复杂。
更好的是制作一个没有假设的自包含辅助类,而不是明确定义的输入和输出:
class SpreadsheetCreator
def initialize(foos)
@foos = foos
end
def string
book = Spreadsheet::Workbook.new
sheet = book.create_worksheet(name: 'Sheet1')
fields = Foo.columns
sheet.row(0).concat(fields)
@foos.each_with_index do |foo, index|
fields.each do |field|
sheet.row(index + 1).push foo.field
end
end
spreadsheet = StringIO.new
book.write spreadsheet
spreadsheet.string
end
end
然后你重写的控制器有一个明确的交接,并保持对控制器本身输出内容的完全控制:
respond_to do |format|
format.html { standard_index } # Has link to format xls
format.xls do
spreadsheet = SpreadsheetCreator.new(@foos)
send_data spreadsheet.string, filename: "foos.xls", type: "application/vnd.ms-excel"
end
end
将责任交给某个神秘模块通常是你反对谷物的标志。