2015-07-24 8 views
6

Mam kontroler szyn z blokiem rescue_from, w którym nazywam się render.request.format w rescue_from block

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

    private 

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

Najdziwniejsze jest to, że nawet jeśli mam widok error.js.erb, szyny będą zawsze wykorzystywać error.html.erb, nawet jeżeli wniosek jest JS:

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

a nie jak w skróconym dzienniku powyżej mówi renderuje się jako JS, ale nadal używa pliku HTML. Numer .js.erb znajduje się w odpowiednim miejscu i renderowanie widoków JS, gdy nie ma włączonego rescue_from, działa dobrze.

Co tu się dzieje?

Update 1: Stworzyłem test repository aby zademonstrować problem

aktualizacji 2znalazłem rozwiązanie (patrz niżej). Czy ktokolwiek może zaproponować bardziej ogólne rozwiązanie, takie jak te poniżej, czy możesz mi powiedzieć, dlaczego byłoby to niemożliwe lub naprawdę zły pomysł? Nagroda jest nadal otwarta.

  • Czy jest sens, aby utworzyć żądanie rozwijane, aby ustawić self.formats w ActionController::Rescue.process_actionlub
  • się naprawdę szalona i spróbować wznowić stos jeden poziom głębiej niż gdzie błąd powstał
+0

Czy próbowałeś "błąd" renderowania, format: request.format'? – eirikir

+0

Mam zaktualizowane pytanie z linkiem do repozytorium testów. Jeśli dodaję 'formats: request.format', wyświetli się komunikat, że nie może znaleźć szablonu do renderowania. – amiuhle

Odpowiedz

5

Rozwiązanie

Zrobiłem kilka debugowania i kopania wokół w źródłach szyn i znalazł rozwiązanie sobie:

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

Wyjaśnienie

Wywołanie bloku rescue_from dzieje w ActionController::Rescue.process_action. Jeśli wystąpi błąd, blok zostanie wywołany. Jeśli nie ma błędów, ostatecznie ActionController::Rendering.process_action zostanie sprawdzony które po prostu ustawia self.formats:

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

Oto pełna StackTrace między ActionController::Rescue.process_action a faktycznym działaniem sterownika.

#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 

Oto pełna StackTrace gdy wystąpi błąd (rzucony w 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 

Więc moim problemem było rzeczywiście, że błąd jest podniesione w before_action, który jest obsługiwany przez AbstractController::Callbacks.process_action i zdarza się, że przed ActionController::Rendering.process_action można ustawić self.formats.

Jeśli błąd został wywołany w samym działaniu, ustawienie self.formats jest już ustawione, a poprawny widok zostanie zrenderowany bez ustawień self.formats w bloku rescue_from.

Powiązane problemy