Ruby-on-rails Rails 4:如何创建使用资产管道的自定义 404 页面?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24235805/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 23:42:59  来源:igfitidea点击:

Rails 4: How do I create a custom 404 page that uses the asset pipeline?

ruby-on-railsruby-on-rails-4error-handlingasset-pipeline

提问by Avery

There are many solutions for creating customized error handling pages, but almost none for Rails 4:

创建自定义错误处理页面有很多解决方案,但对于 Rails 4 几乎没有:

The standard answer of encouraging people to modify 404.htmlin /publicdoesn't work for me because I want to use the CSS theme that resides in the asset pipeline. Is there a way that html files can access those styles defined in the asset pipeline?If not, is there a way to create a custom error handler that has access to the pipeline?

标准答案鼓励人们修改404.html/public我不工作,因为我想用CSS主题驻留在资产管道。有没有办法让 html 文件可以访问资产管道中定义的那些样式?如果没有,有没有办法创建一个可以访问管道的自定义错误处理程序?

回答by Douglas Lovell

For Rails 4.1 I like this answer, add an asset typebetter; however I have not tried it. On Rails 4.0.8, these three references helped me:

对于 Rails 4.1 我喜欢这个答案,更好地添加资产类型;但是我还没有尝试过。在 Rails 4.0.8 上,这三个参考资料帮助了我:

  1. Dynamic error pagesis the second reference in the question. This worked just fine for me.

  2. Custom error pagesmay have cribbed from the first reference, or the other way around, but goes the extra mile by adding some information about testing with Capybara.

  3. I did not do the Capybara testing because I didn't want to change the test configuration; however, RSpec-Rails Request Specsclued me in to test these requests independently and see that they complete and return the correct content.

  1. 动态错误页面是问题中的第二个参考。这对我来说很好。

  2. 自定义错误页面可能从第一个参考文献中抄袭,或者相反,但通过添加一些有关使用 Capybara 进行测试的信息,更进一步。

  3. 我没有做 Capybara 测试,因为我不想改变测试配置;然而,RSpec-Rails 请求规范提示我独立测试这些请求,并查看它们是否完成并返回正确的内容。

What follows is a nutshell description of what is taught by the three references:

以下是对三篇参考文献所教内容的简要描述:

  1. Add the following setting to config/environments/production.rb

    # Route exceptions to the application router vs. default
    config.exceptions_app = self.routes
    
  2. Edit the routing configuration, config/routes.rbto direct the error pages to an errors controller

      # error pages
      %w( 404 422 500 503 ).each do |code|
        get code, :to => "errors#show", :code => code
      end
    

    will route the 404, 422, 500, and 503 page requests to the showaction of the errorscontroller with a parameter codethat has the value of the status code.

  3. Create the controller, app/controllers/errors_controller.rb. Here is the entire content:

    class ErrorsController < ApplicationController
    
      def show
        status_code = params[:code] || 500
        flash.alert = "Status #{status_code}"
        render status_code.to_s, status: status_code
      end
    
    end
    

    My preference was to set a status message on flash.alert

  4. Create the pages themselves. I use .erbHere is app/views/errors/500.html.erb

    <p>Our apology.  Your request caused an error.</p>
    <%= render 'product_description' %>
    

    So you see that you can render a partial. The page renders with all of the layout boilerplate from app/views/layouts/application.html.erbor any other layout boilerplate that you have configured. That includes the <div id='alert'><%= alert %></div>that displays the status message from the flash.

  5. Tested with RSpec by adding a test file, spec/requests/errors_request_spec.rb. Here is abbreviated content of that file that shows a test of the 500 status page:

    require 'rails_helper'
    
    RSpec.describe "errors", :type => :request do
    
      it "displays the 500 page" do
        get "/500"
        assert_select 'div#alert', 'Status 500'
        assert_select 'div[itemtype]'
      end
    
    end
    

    The first assertion checks for the flash alert. The second assertion checks for the partial.

  1. 将以下设置添加到 config/environments/production.rb

    # Route exceptions to the application router vs. default
    config.exceptions_app = self.routes
    
  2. 编辑路由配置,config/routes.rb将错误页面定向到错误控制器

      # error pages
      %w( 404 422 500 503 ).each do |code|
        get code, :to => "errors#show", :code => code
      end
    

    将使用具有状态代码值的参数将404、422、500 和 503 页面请求路由到控制器的show操作。errorscode

  3. 创建控制器,app/controllers/errors_controller.rb。以下是全部内容:

    class ErrorsController < ApplicationController
    
      def show
        status_code = params[:code] || 500
        flash.alert = "Status #{status_code}"
        render status_code.to_s, status: status_code
      end
    
    end
    

    我的偏好是设置状态消息 flash.alert

  4. 自己创建页面。我用.erb这里是app/views/errors/500.html.erb

    <p>Our apology.  Your request caused an error.</p>
    <%= render 'product_description' %>
    

    所以你看到你可以渲染部分。该页面使用app/views/layouts/application.html.erb您配置的所有布局样板或任何其他布局样板呈现。这包括<div id='alert'><%= alert %></div>显示来自闪存的状态消息。

  5. 通过添加测试文件,使用 RSpec 进行测试spec/requests/errors_request_spec.rb。以下是该文件的缩写内容,显示了 500 状态页面的测试:

    require 'rails_helper'
    
    RSpec.describe "errors", :type => :request do
    
      it "displays the 500 page" do
        get "/500"
        assert_select 'div#alert', 'Status 500'
        assert_select 'div[itemtype]'
      end
    
    end
    

    第一个断言检查闪光警报。第二个断言检查部分。

回答by Richard Peck

We've made a gem which does this for you: exception_handler.

我们制作了一个 gem,可以为您执行此操作:exception_handler.

There is also a great tutorial here.

还有一个伟大的教程在这里

I also wrote an extensive answer on the subject here.

我也写了一个广泛的答案关于这个问题在这里

Middleware

中间件

# config/application.rb
config.exceptions_app = ->(env) { ExceptionController.action(:show).call(env) }

Controller

控制器

# app/controllers/exception_controller.rb
class ExceptionController < ApplicationController
  respond_to :json, :js, :html
  before_action :set_status

  def show
    respond_with @status
  end

  private

  def set_status
    def status
      @exception = env['action_dispatch.exception']
      @status    = ActionDispatch::ExceptionWrapper.new(env, @exception).status_code
      @response  = ActionDispatch::ExceptionWrapper.rescue_responses[@exception.class.name]
    end
  end
end

View

看法

# app/views/exception/show.html.erb
<h1>404 error</h1>

This is very simple version - I can explain more if you wish.

这是非常简单的版本 - 如果您愿意,我可以解释更多。

Basically, you need to hook into the config.exceptions_appmiddleware, it will capture any exception in the middlewarestack (as opposed to rendering the entire environment), allowing you to send the request to your own controller#action.

基本上,您需要挂钩到config.exceptions_app中间件,它会捕获middleware堆栈中的任何异常(而不是渲染整个环境),从而允许您将请求发送到您自己的controller#action.

If you comment, I'll help you out some more if you want!

如果您发表评论,如果您愿意,我会为您提供更多帮助!