Pavel
Pavel

Reputation: 1974

404 status: missing layout

When record is not found I render 404 page. The problem is it's doesn't have application layout although 403 works fine

class ApplicationController < ActionController::Base

  rescue_from ActiveRecord::RecordNotFound, with: :render_404

  def render_404
    render file: 'public/404.html', status: 404, layout: 'application'
  end

  def render_403
    render file: 'public/403.html', status: 403, layout: 'application'
  end

end

Upvotes: 1

Views: 181

Answers (2)

Richard Peck
Richard Peck

Reputation: 76774

We have a better way of capturing exceptions:

(Here's where we got it from)


Capture

A much more efficient way of capturing exceptions is to use the exceptions_app method

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

--

Process

Secondly, you should process the caught exception. You can do this by sending the request to a controller method (we use ExceptionController#show):

#app/controllers/exception_controller.rb
class ExceptionController < ApplicationController

  #Response
  respond_to :html, :xml, :json

  #Dependencies
  before_action :status

  #Layout
  layout :layout_status

  ####################
  #      Action      #
  ####################

  #Show
  def show
    respond_with status: @status
  end

  ####################
  #   Dependencies   #
  ####################

  protected

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

  #Format
  def details
    @details ||= {}.tap do |h|
      I18n.with_options scope: [:exception, :show, @response], exception_name: @exception.class.name, exception_message: @exception.message do |i18n|
        h[:name]    = i18n.t "#{@exception.class.name.underscore}.title", default: i18n.t(:title, default: @exception.class.name)
        h[:message] = i18n.t "#{@exception.class.name.underscore}.description", default: i18n.t(:description, default: @exception.message)
      end
    end
  end
  helper_method :details

  ####################
  #      Layout      #
  ####################

  private

  #Layout
  def layout_status
    @status.to_s == "404" ? "application" : "error"
  end
end

--

Show

Finally, you can output the message you've received, with custom layouts per error:

#app/views/exception/show.html.erb
<div class="box">
    <h1><%= details[:name] %></h1>
    <p><%= details[:message] %></p>
</div>

Upvotes: 1

roman-roman
roman-roman

Reputation: 2796

Are you sure your custom rescue_from is being executed?.. I don't think so. Maybe another exception is thrown, not ActiveRecord::RecordNotFound.

The thing is that public/404.html is rendered for 404 error by rails by default, with no layout. If you want to tweak this behavior, remove that public/* files and put them under app/views folder, so you have full control and rails default behavior won't confuse you.

Upvotes: 1

Related Questions