【问题标题】:Dynamic error pages in Rails 3Rails 3 中的动态错误页面
【发布时间】:2011-07-16 21:42:29
【问题描述】:

在 Rails 2.3.x 中,您可以像这样覆盖 render_optional_error_file

# ApplicationController.rb
protected
  def render_optional_error_file(status_code)
    render :template => "errors/500", :status => 500, :layout => 'application'
  end

但是,Rails 3 不再具有render_optional_error_file。相反,您需要覆盖 rescue_action_in_public,您可以这样做:

# config/initializers/error_page.rb
module ActionDispatch
  class ShowExceptions

    protected    
      def rescue_action_in_public(exception)
        status = status_code(exception).to_s

        template = ActionView::Base.new(["#{Rails.root}/app/views"])
        if ["404"].include?(status)
          file = "/errors/404.html.erb"
        else
          file = "/errors/500.html.erb"
        end        
        body = template.render(:file => file)

        render(status, body)
      end

  end
end

这可行,但不使用应用程序的布局。但是,如果您像这样指定布局路径:

body = template.render(:file => file, :layout => "layouts/application") # line 15

您会收到一个Error during failsafe response: ActionView::Template::Error

application.html.erb:4 的第 4 行是:

<%= stylesheet_link_tag "app", "jquery-ui", "jquery.fancybox", :cache => "all" %>

通常用于呈现模板的 ActionView 都没有加载。

堆栈跟踪是:

  /var/lib/gems/1.8/gems/actionpack-3.0.5/lib/action_view/helpers/asset_tag_helper.rb:794:in `join'
  /var/lib/gems/1.8/gems/actionpack-3.0.5/lib/action_view/helpers/asset_tag_helper.rb:794:in `rails_asset_id'
  /var/lib/gems/1.8/gems/actionpack-3.0.5/lib/action_view/helpers/asset_tag_helper.rb:817:in `rewrite_asset_path'
  /var/lib/gems/1.8/gems/actionpack-3.0.5/lib/action_view/helpers/asset_tag_helper.rb:746:in `compute_public_path'
  /var/lib/gems/1.8/gems/actionpack-3.0.5/lib/action_view/helpers/asset_tag_helper.rb:424:in `path_to_stylesheet'
  /var/lib/gems/1.8/gems/actionpack-3.0.5/lib/action_view/helpers/asset_tag_helper.rb:875:in `ensure_stylesheet_sources!'
  /var/lib/gems/1.8/gems/actionpack-3.0.5/lib/action_view/helpers/asset_tag_helper.rb:874:in `each'
  /var/lib/gems/1.8/gems/actionpack-3.0.5/lib/action_view/helpers/asset_tag_helper.rb:874:in `ensure_stylesheet_sources!'
  /var/lib/gems/1.8/gems/actionpack-3.0.5/lib/action_view/helpers/asset_tag_helper.rb:512:in `stylesheet_link_tag'
  /data/sites/fundraisers-stage/releases/20110316194843/app/views/layouts/application.html.erb:4:in `_app_views_layouts_application_html_erb___19482063_70294907435920_0'
  /var/lib/gems/1.8/gems/actionpack-3.0.5/lib/action_view/template.rb:135:in `send'
  /var/lib/gems/1.8/gems/actionpack-3.0.5/lib/action_view/template.rb:135:in `render'
  /var/lib/gems/1.8/gems/activesupport-3.0.5/lib/active_support/notifications.rb:54:in `instrument'
  /var/lib/gems/1.8/gems/actionpack-3.0.5/lib/action_view/template.rb:127:in `render'
  /var/lib/gems/1.8/gems/actionpack-3.0.5/lib/action_view/render/layouts.rb:80:in `_render_layout'
  /var/lib/gems/1.8/gems/actionpack-3.0.5/lib/action_view/render/rendering.rb:62:in `_render_template'
  /var/lib/gems/1.8/gems/activesupport-3.0.5/lib/active_support/notifications.rb:52:in `instrument'
  /var/lib/gems/1.8/gems/activesupport-3.0.5/lib/active_support/notifications/instrumenter.rb:21:in `instrument'
  /var/lib/gems/1.8/gems/activesupport-3.0.5/lib/active_support/notifications.rb:52:in `instrument'
  /var/lib/gems/1.8/gems/actionpack-3.0.5/lib/action_view/render/rendering.rb:56:in `_render_template'
  /var/lib/gems/1.8/gems/actionpack-3.0.5/lib/action_view/render/rendering.rb:26:in `render'
  /data/sites/fundraisers-stage/releases/20110316194843/config/initializers/error_pages.rb:15:in `rescue_action_in_public'

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 exception-handling error-handling actionview


    【解决方案1】:

    在 rails 3.2 中,它比这更容易:

    将此添加到config/application.rb

    config.exceptions_app = self.routes
    

    这会导致通过路由器路由错误。然后你只需添加到config/routes.rb:

    match "/404", :to => "errors#not_found"
    

    我从 José Valim 的博文“My five favorite hidden features in Rails 3.2”中的第 3 项中获得了此信息。

    【讨论】:

    【解决方案2】:

    我建议改用 rescue_from。您只需从特定错误中解救,而不是覆盖rescue_action_in_public。这在处理用户定义的错误或特定于控制器的错误时特别有用。

    # ApplicationController
    rescue_from ActionController::RoutingError, :with => :render_404
    rescue_from ActionController::UnknownAction, :with => :render_404
    rescue_from ActiveRecord::RecordNotFound, :with => :render_404
    rescue_from MyApp::CustomError, :with => :custom_error_resolution
    
    def render_404
      if /(jpe?g|png|gif)/i === request.path
        render :text => "404 Not Found", :status => 404
      else
        render :template => "shared/404", :layout => 'application', :status => 404
      end
    end
    
    # UsersController
    rescue_from MyApp::SomeReallySpecificUserError, :with => :user_controller_resolution
    

    http://api.rubyonrails.org/classes/ActiveSupport/Rescuable/ClassMethods.html

    【讨论】:

    • 使用rescue_from 的问题在于它会停止错误链。我不希望错误链停止;我希望它继续传播。这样,exception_notifier 仍然可以工作。
    • 明白了;我使用 hoptoad,所以我通常最终会执行“rescue_from Exception”作为包罗万象的方法,将错误通知 hoptoad,然后执行一些动态错误处理。你可以试试... render(:template => file, :layout => '/layouts/application', :status => 404) 看看是否可行?
    • 这没什么区别——和以前一样的回溯。我需要找到一些方法来按预期设置 ActionView 的上下文。或许我可以直接调用它的渲染函数?
    • 如果您将代码设为模块并将其包含在 ApplicationController 中会有所不同吗?
    • 我该怎么做?它目前是一个模块:module ActionDispatch class ShowExceptions.
    【解决方案3】:

    异常通知器有一个名为notify_about_exception 的方法来按需启动错误通知。

    class ApplicationController < ActionController::Base
      include ExceptionNotification::Notifiable
    
      rescue_from Exception, :with => :render_all_errors
    
      def render_all_errors(e)
        log_error(e) # log the error
        notify_about_exception(e) # send the error notification
    
        # now handle the page
        if e.is_a?(ActionController::RoutingError)
          render_404(e)
        else
          render_other_error(e)
        end
      end
    
      def render_404_error(e)
       # your code
      end
    
      def render_other_error(e)
       # your code
      end
    end
    

    【讨论】:

    • 这很有用,但不是通用的——它只适用于特定的 ExceptionNotifier,如果没有安装则会失败。我正在使用github.com/railsware/exception_notification。我想你可以测试defined?(),但实际上,我只想覆盖渲染代码,而不是整个堆栈。
    【解决方案4】:

    我也遇到过这样的问题。问题是由于 attachment_fu gem 或插件。只需将其卸载并使用任何其他插件或 gem 即可解决您的问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-02
      • 2014-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-13
      相关资源
      最近更新 更多