【发布时间】:2014-09-08 23:56:30
【问题描述】:
我正在 Rails 中编写一个应用程序,我想从 API 中获取大量信息——我通过 Enumerator 对象以 CSV 导出的形式流式传输这些信息。我想抢救在枚举器中调用的错误。
控制器:枚举器
def csv_lines( url )
Enumerator.new do |y|
per_page = 200
# Parse parameters and get shelf information
_params = BrowseScraper.get_params(url)
shelf = BrowseScraper.get_preso( _params, 0 )
total_items = shelf['response']['total_results']['all'].to_i
total_pages = ( total_items / per_page.to_f ).ceil
shelf_info = BrowseScraper.crawl_ids( shelf['response']['query']['category'] )
y << BrowseScraper.csv_header(url, shelf_info, total_items, ["Tool ID", "Name", "Price", "URL"])
total_pages.times { |i| y << BrowseScraper.csv_body( _params, per_page, i+1) }
end
end
以下函数会引发错误,但我无法在枚举器之外捕获它们:
模型:方法
def self.get_params
response = open(url)
raise if response.code != 200
end
控制器:显示
def export
url = params[:url]
raise StandardError, "Please enter a Browse URL below" if !url || url.empty?
respond_to do |format|
format.csv do
render_csv(url)
end
format.html { render_csv(url) }
end
rescue => e
flash[:error] = e.message
redirect_to scraper_path
end
private
def render_csv( url )
set_file_headers
set_streaming_headers
response.status = 200
# Rails should iterate this enumerator
self.response_body = csv_lines(url)
end
def set_file_headers( name = "browse_export" )
headers["Content-Type"] ||= 'text/csv'
headers["Content-Disposition"] = "attachment; filename=\"#{name}.csv\""
headers["Content-Transfer-Encoding"] = "binary"
headers["Last-Modified"] = Time.now.ctime.to_s
end
def set_streaming_headers
#nginx doc: Setting this to "no" will allow unbuffered responses suitable for Comet and HTTP streaming applications
headers['X-Accel-Buffering'] = 'no'
headers["Cache-Control"] ||= "no-cache"
headers.delete("Content-Length")
end
修复export 中引发的错误有效。挽救 Enumerator 中的错误是可行的(例如:
Enumerator do |y|
begin
y << BrowseScraper.get_params(_params)
rescue => e
Rails.logger.error "Failed to get parameters: #{e.message}"
end
end
如何在 Enumerator 之外抢救异常,以便可以使用 flash 消息正确重定向用户?如何从 Enumerator 对象中传递异常? 不让我用 Enumerator 来拯救它的原因是什么:
def method
Enumerator do |y|
y << BrowseScraper.get_params(_params)
end
rescue => e
Rails.logger.error "Error in Enumerator is #{e.message}"
end
【问题讨论】:
-
Enumerator类没有什么特别之处,您可以在包装开始/救援块中拯救未捕获的异常。在您的method方法中,您正在拯救StandardError- 省略异常类时的默认值。你确定你的代码会引发这种异常或其子类吗? -
嘿@DavidUnric,感谢您的回复。我确保只抛出
StandardErrors 或编写基于StandardErrors 的类。我什至可以看到我正在挽救Enumerator中的正确错误。但我无法在外面拯救它。这是一个实例问题,我需要在Enumerator的第一个实例上拯救它吗? -
除非异常在 Enumerator 中被救出,否则它会传播到外部范围。以下代码在运行
def method; (1..10).each {|i| raise StandardError if i > 5; p i}; rescue; p 'gotcha'; end时会打印数字 1 到 5,然后字符串 'gotcha' 作为异常被救出。 -
您需要更具体一些,并举例说明您实际使用的是
Enumerator的哪个实例。 -
该实例似乎由self.response_body 调用,然后迭代枚举器。我想我提出问题的方式不再有效。看起来你可以从
Enumerators中拯救出来,但由于迭代是由response_body完成的,我没有办法访问我需要拯救它的部分......所以我想我需要做我的拥有覆盖它的response_body或类似的东西。
标签: ruby-on-rails ruby exception enumerator rescue