Rails' 导出 csv 函数 "undefined method `export' for nil:NilClass"
Rails' export csv function "undefined method `export' for nil:NilClass"
我正在 Rails 存储库的 Ruby 中导出到 csv 文件的功能,我快完成了。但是,当我按下“全部导出”按钮时,出现 undefined method `export' for nil:NilClass
错误。日志显示 format.csv { send_data @foos.export, filename: "foos-#{Date.today}.csv" }
出错了。请问我错过了什么?
这是模特
class Foo < ApplicationRecord
has_many :bars
def export
[id, name, foos.map(&:name).join(' ')]
end
end
这是控制器的一部分
def index
@foos = Foo.all
end
def export
all = Foo.all
attributes = %w{name}
CSV.generate(headers: true) do |csv|
csv << attributes
all.each do |foo|
csv << attributes.map{ |attr| foo.send(attr) }
end
respond_to do |format|
format.csv { send_data @foos.export, filename: "foos-#{Date.today}.csv" }
end
end
end
def name
"#{foo_id} #{name}"
end
这是视图
<a href="/export.csv"><button class="btn btn-success">export all</button></a>
这是路线
Rails.application.routes.draw do
resources :foos
get :export, controller: :foos
root "foos#index"
end
这是耙子 (lib/tasks/export.rb)
namespace :export do
task foo: :environment do
file_name = 'exported_foo.csv'
csv_data = Foo.to_csv
File.write(file_name, csv_data)
end
end
首先创建一个 service object 来收集记录和 returns CSV,以便您可以单独测试 CSV 生成:
# app/services/foo_export_service.rb
# Just a Plain Old Ruby Object that converts a collection of foos into CSV
class FooExportService
# The initializer gives us a good place to setup our service
# @param [Enumerable] foo - an array or collection of records
def initialize(foos)
@headers = %w{name} # the attributes you want to use
@foos = foos
end
# performs the actual work
# @return [String]
def perform
CSV.generate do |csv|
@foos.each do |foo|
csv << foo.serializable_hash.slice(@headers).values
end
end
end
# A convenient factory method which makes stubbing the
# service easier
# @param [Enumerable] foos - an array or collection of records
# @return [String]
def self.perform(foos)
new(foos).perform
end
end
# example usage
FooExportService.perform(Foo.all)
并非 Rails 应用程序中的所有内容都需要塞入模型、视图或控制器中。他们已经有足够的责任。如果您确实需要,这还可以让您在 rake 任务中重新使用代码。
这只是遍历集合并使用 Rails 内置序列化功能将模型实例转换为可以序列化为 CSV 的哈希值。它还使用了 Hash#slice
也重新排序哈希键的事实。
在您的控制器中,您只需使用服务对象:
class FoosController
def export
@foos = Foo.all
respond_to do |format|
format.csv do
send_data FooExportService.perform(@foos),
filename: "foos-#{Date.today}.csv"
end
end
end
end
您一开始甚至不需要单独的 export
操作。只需使用 MimeResponds 将 CSV 作为可用的响应格式添加到索引中:
class FoosController
def index
# GET /foos
# GET /foos.csv
@foos = Foo.all
respond_to do |format|
format.html
format.csv do
send_data FooExportService.perform(@foos),
filename: "foos-#{Date.today}.csv"
end
end
end
end
<%= link_to("Export as CSV", foos_path(format: :csv)) %>
我正在 Rails 存储库的 Ruby 中导出到 csv 文件的功能,我快完成了。但是,当我按下“全部导出”按钮时,出现 undefined method `export' for nil:NilClass
错误。日志显示 format.csv { send_data @foos.export, filename: "foos-#{Date.today}.csv" }
出错了。请问我错过了什么?
这是模特
class Foo < ApplicationRecord
has_many :bars
def export
[id, name, foos.map(&:name).join(' ')]
end
end
这是控制器的一部分
def index
@foos = Foo.all
end
def export
all = Foo.all
attributes = %w{name}
CSV.generate(headers: true) do |csv|
csv << attributes
all.each do |foo|
csv << attributes.map{ |attr| foo.send(attr) }
end
respond_to do |format|
format.csv { send_data @foos.export, filename: "foos-#{Date.today}.csv" }
end
end
end
def name
"#{foo_id} #{name}"
end
这是视图
<a href="/export.csv"><button class="btn btn-success">export all</button></a>
这是路线
Rails.application.routes.draw do
resources :foos
get :export, controller: :foos
root "foos#index"
end
这是耙子 (lib/tasks/export.rb)
namespace :export do
task foo: :environment do
file_name = 'exported_foo.csv'
csv_data = Foo.to_csv
File.write(file_name, csv_data)
end
end
首先创建一个 service object 来收集记录和 returns CSV,以便您可以单独测试 CSV 生成:
# app/services/foo_export_service.rb
# Just a Plain Old Ruby Object that converts a collection of foos into CSV
class FooExportService
# The initializer gives us a good place to setup our service
# @param [Enumerable] foo - an array or collection of records
def initialize(foos)
@headers = %w{name} # the attributes you want to use
@foos = foos
end
# performs the actual work
# @return [String]
def perform
CSV.generate do |csv|
@foos.each do |foo|
csv << foo.serializable_hash.slice(@headers).values
end
end
end
# A convenient factory method which makes stubbing the
# service easier
# @param [Enumerable] foos - an array or collection of records
# @return [String]
def self.perform(foos)
new(foos).perform
end
end
# example usage
FooExportService.perform(Foo.all)
并非 Rails 应用程序中的所有内容都需要塞入模型、视图或控制器中。他们已经有足够的责任。如果您确实需要,这还可以让您在 rake 任务中重新使用代码。
这只是遍历集合并使用 Rails 内置序列化功能将模型实例转换为可以序列化为 CSV 的哈希值。它还使用了 Hash#slice
也重新排序哈希键的事实。
在您的控制器中,您只需使用服务对象:
class FoosController
def export
@foos = Foo.all
respond_to do |format|
format.csv do
send_data FooExportService.perform(@foos),
filename: "foos-#{Date.today}.csv"
end
end
end
end
您一开始甚至不需要单独的 export
操作。只需使用 MimeResponds 将 CSV 作为可用的响应格式添加到索引中:
class FoosController
def index
# GET /foos
# GET /foos.csv
@foos = Foo.all
respond_to do |format|
format.html
format.csv do
send_data FooExportService.perform(@foos),
filename: "foos-#{Date.today}.csv"
end
end
end
end
<%= link_to("Export as CSV", foos_path(format: :csv)) %>