request_format in rescue_from block

时间:2015-07-24 14:28:00

标签: ruby-on-rails

我有一个带rescue_from块的rails控制器,我在其中调用render

class SomeController < ApplicationController
  rescue_from Some::Error, :some_error

  private

  def some_error error
    @error = error
    render 'error'
  end
end

奇怪的是,即使我有error.js.erb视图,rails也会始终使用error.html.erb,即使请求是JS

Started GET /some/1
Processing by SomeController#show as JS
...
Rendered some/error.html.erb

上面的缩短日志中没有说它如何呈现为JS,但它仍然使用HTML文件。 .js.erb位于正确的位置,并且当没有rescue_from涉及的工作正常时,呈现JS视图。

这里发生了什么?

更新1 我创建了test repository来演示问题

更新2 我找到了解决方案(见下文)。任何人都可以提出一个更通用的解决方案,如下面的那些,或者你能告诉我为什么这将是不可能的或一个非常糟糕的主意?赏金仍然开放。

  • self.formats
  • 中设置拉取请求以设置ActionController::Rescue.process_action是否有意义
  • 变得非常疯狂,并尝试将错误重置的位置比错误提升的位置更深一层次

1 个答案:

答案 0 :(得分:5)

<强>解决方案

我在rails源代码中进行了一些调试和挖掘,并自己找到了解决方案:

def error
  @error = error
  self.formats = request.formats.map(&:ref).compact
  render 'error'
end

<强>解释

ActionController::Rescue.process_action中调用rescue_from阻止。如果有错误,将调用该块。如果没有错误,最终会调用ActionController::Rendering.process_action来设置self.formats

def process_action(*) #:nodoc:
  self.formats = request.formats.map(&:ref).compact
  super
end

这是ActionController::Rescue.process_action与实际控制器操作之间的完整堆栈跟踪。

#0  TestController.index at /tmp/rescue_from/app/controllers/test_controller.rb:11
#1  ActionController::ImplicitRender.send_action(method#String, *args#Array) at /usr/local/Cellar/rbenv/0.4.0/versions/2.2.2/lib/ruby/gems/2.2.0/gems/actionpack-4.2.3/lib/action_controller/metal/implicit_render.rb:4
#2  AbstractController::Base.process_action(action#NilClass, *args#Array) at /usr/local/Cellar/rbenv/0.4.0/versions/2.2.2/lib/ruby/gems/2.2.0/gems/actionpack-4.2.3/lib/abstract_controller/base.rb:198
#3  ActionController::Rendering.process_action(action, *args) at /usr/local/Cellar/rbenv/0.4.0/versions/2.2.2/lib/ruby/gems/2.2.0/gems/actionpack-4.2.3/lib/action_controller/metal/rendering.rb:10
#4  block in AbstractController::Callbacks.process_action(action#NilClass, *args#Array) at /usr/local/Cellar/rbenv/0.4.0/versions/2.2.2/lib/ruby/gems/2.2.0/gems/actionpack-4.2.3/lib/abstract_controller/callbacks.rb:20
ͱ-- #5  Proc.call(*args) at /usr/local/Cellar/rbenv/0.4.0/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.3/lib/active_support/callbacks.rb:115
#6  ActiveSupport::Callbacks::Filters::End.call(env#ActiveSupport::Callbacks::Filters::Environment) at /usr/local/Cellar/rbenv/0.4.0/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.3/lib/active_support/callbacks.rb:115
#7  block (2 levels) in ActiveSupport::Callbacks::CallbackChain.compile at /usr/local/Cellar/rbenv/0.4.0/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.3/lib/active_support/callbacks.rb:553
ͱ-- #8  Proc.call(*args) at /usr/local/Cellar/rbenv/0.4.0/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.3/lib/active_support/callbacks.rb:503
#9  ActiveSupport::Callbacks::CallbackSequence.call(*args#Array) at /usr/local/Cellar/rbenv/0.4.0/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.3/lib/active_support/callbacks.rb:503
#10 ActiveSupport::Callbacks.run_callbacks(kind#Symbol, &block#Proc) at /usr/local/Cellar/rbenv/0.4.0/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.3/lib/active_support/callbacks.rb:88
#11 AbstractController::Callbacks.process_action(action#NilClass, *args#Array) at /usr/local/Cellar/rbenv/0.4.0/versions/2.2.2/lib/ruby/gems/2.2.0/gems/actionpack-4.2.3/lib/abstract_controller/callbacks.rb:19
#12 ActionController::Rescue.process_action(action#NilClass, *args#Array) at /usr/local/Cellar/rbenv/0.4.0/versions/2.2.2/lib/ruby/gems/2.2.0/gems/actionpack-4.2.3/lib/action_controller/metal/rescue.rb:29

当出现错误(在before_action中抛出)时,这是一个完整的堆栈跟踪:

--> #0  TestController.standard_error(error#RuntimeError) at /Users/timou/tmp/rescue_from/app/controllers/test_controller.rb:20
ͱ-- #1  Method.call(*args) at /usr/local/Cellar/rbenv/0.4.0/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.3/lib/active_support/rescuable.rb:80
#2  ActiveSupport::Rescuable.rescue_with_handler(exception#RuntimeError) at /usr/local/Cellar/rbenv/0.4.0/versions/2.2.2/lib/ruby/gems/2.2.0/gems/activesupport-4.2.3/lib/active_support/rescuable.rb:80
#3  ActionController::Rescue.rescue_with_handler(exception#RuntimeError) at /usr/local/Cellar/rbenv/0.4.0/versions/2.2.2/lib/ruby/gems/2.2.0/gems/actionpack-4.2.3/lib/action_controller/metal/rescue.rb:15
#4  rescue in ActionController::Rescue.process_action(action#NilClass, *args#Array) at /usr/local/Cellar/rbenv/0.4.0/versions/2.2.2/lib/ruby/gems/2.2.0/gems/actionpack-4.2.3/lib/action_controller/metal/rescue.rb:32
#5  ActionController::Rescue.process_action(action#NilClass, *args#Array) at /usr/local/Cellar/rbenv/0.4.0/versions/2.2.2/lib/ruby/gems/2.2.0/gems/actionpack-4.2.3/lib/action_controller/metal/rescue.rb:29

所以我的问题实际上是before_action引发的错误,由AbstractController::Callbacks.process_action处理并在ActionController::Rendering.process_action设置self.formats之前发生。

如果操作本身出现错误,则已设置self.formats,并且在self.formats块中没有设置rescue_from的情况下呈现正确的视图。