web-dev-qa-db-fra.com

Rails 4: Comment créer une page 404 personnalisée qui utilise le pipeline d'actifs?

Il existe de nombreuses solutions pour créer des pages de gestion des erreurs personnalisées, mais presque aucune pour Rails 4:

La réponse standard d'encourager les gens à modifier 404.html dans /public ne fonctionne pas pour moi car je souhaite utiliser le thème CSS qui réside dans le pipeline des ressources. Existe-t-il un moyen pour les fichiers html d'accéder aux styles définis dans le pipeline d'actifs? Sinon, existe-t-il moyen de créer un gestionnaire d'erreurs personnalisé qui a accès au pipeline?

26
Avery

Pour Rails 4.1 J'aime cette réponse, ajoutez un type d'actif mieux; mais je ne l'ai pas essayé. Sur Rails 4.0. 8, ces trois références m'ont aidé:

  1. Pages d'erreur dynamiques est la deuxième référence dans la question. Cela a très bien fonctionné pour moi.

  2. Pages d'erreur personnalisées peut avoir été corrigé à partir de la première référence, ou l'inverse, mais va plus loin en ajoutant des informations sur les tests avec Capybara.

  3. Je n'ai pas fait le test Capybara parce que je ne voulais pas changer la configuration du test; cependant, RSpec-Rails Request Specs m'a demandé de tester ces demandes indépendamment et de voir qu'elles se terminent et renvoient le contenu correct.

Ce qui suit est une description en bref de ce qui est enseigné par les trois références:

  1. Ajoutez le paramètre suivant à config/environments/production.rb

    # Route exceptions to the application router vs. default
    config.exceptions_app = self.routes
    
  2. Modifiez la configuration de routage, config/routes.rb pour diriger les pages d'erreur vers un contrôleur d'erreurs

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

    achemine les demandes de pages 404, 422, 500 et 503 vers l'action show du contrôleur errors avec un paramètre code qui a la valeur du code d'état.

  3. Créez le contrôleur, app/controllers/errors_controller.rb. Voici tout le contenu:

    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
    

    Ma préférence était de définir un message d'état sur flash.alert

  4. Créez les pages elles-mêmes. J'utilise .erb Voici app/views/errors/500.html.erb

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

    Vous voyez donc que vous pouvez rendre un partiel. La page s'affiche avec tous les passe-partout de mise en page de app/views/layouts/application.html.erb ou tout autre passe-partout de disposition que vous avez configuré. Cela inclut le <div id='alert'><%= alert %></div> qui affiche le message d'état du flash.

  5. Testé avec RSpec en ajoutant un fichier de test, spec/requests/errors_request_spec.rb. Voici le contenu abrégé de ce fichier qui montre un test de la page d'état 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
    

    La première assertion vérifie l'alerte flash. La deuxième assertion vérifie le partiel.

43
Douglas Lovell

Nous avons fait un bijou qui fait cela pour vous: exception_handler .

Il y a aussi un excellent tutoriel ici .

J'ai également écrit une réponse détaillée sur le sujet ici .

Middleware

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

Contrôleur

# 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

Voir

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

Ceci est une version très simple - je peux vous expliquer plus si vous le souhaitez.

Fondamentalement, vous devez vous connecter au config.exceptions_app middleware, il capturera toute exception dans la pile middleware (par opposition au rendu de l'environnement entier), vous permettant d'envoyer la demande à votre propre controller#action.

Si vous commentez, je vais vous aider un peu plus si vous le souhaitez!

5
Richard Peck