Rails 3 - development errors in production mode
Asked Answered
A

4

7

Im using Rails, Passenger (both are 3.0.5) and Nginx on my production server. As I heard, Rails should show public/404.html or public/500.html instead of development errors like ActiveRecord::RecordNotFound or Unknown action but that doesn't happen. I've tried to delete config.ru file and set rack_env or rails_env in nginx.conf but nothing helped.

Here is my nginx.conf:

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    passenger_root /home/makk/.rvm/gems/ruby-1.9.2-p0/gems/passenger-3.0.5;
    passenger_ruby /home/makk/.rvm/bin/passenger_ruby;
    #passenger_ruby /home/makk/.rvm/wrappers/ruby-1.9.2-p0/ruby;

    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    keepalive_timeout  65;

    server {
        listen       80;
        server_name  localhost;

        location / {
            root   /home/makk/projects/1server/deploy/current/public;
            index  index.html index.htm;
            passenger_enabled on;
            rack_env production;

            recursive_error_pages on;

            if (-f /home/makk/projects/1server/maintenance.html) {
              return 503;
            }

            error_page 404 /404.html;
            error_page 500 502 504 /500.html;
            error_page 503 @503;
        }

        location @503 {
            error_page 405 = /maintenance.html;

            # Serve static assets if found.
              if (-f $request_filename) {
              break;
            }
            rewrite ^(.*)$ /maintenance.html break;
        }

        location ~ ^(\/phpmyadmin\/)(.*)$ {
        fastcgi_pass    127.0.0.1:9000;
        fastcgi_index   index.php;
        fastcgi_split_path_info         ^(\/phpmyadmin\/)(.*)$;
        fastcgi_param   SCRIPT_FILENAME /usr/share/phpmyadmin/$fastcgi_path_info;
        include         fastcgi_params;
        }
    }
}

It seems that this question duplicates this one but there are no working suggestions.

UPD: I have both development and production apps on same PC. In production Rails ignores config.consider_all_requests_local = false (in /config/environments/production.rb) due to local_request? method. So one of possible solutions is listed below (taken from here):

# config/initializers/local_request_override.rb
module CustomRescue
  def local_request?
    return false if Rails.env.production? || Rails.env.staging?
    super
  end
end

ActionController::Base.class_eval do
  include CustomRescue
end

Or for Rails 3:

class ActionDispatch::Request
 def local?
   false
 end
end
Alcibiades answered 16/3, 2011 at 18:53 Comment(0)
N
2

Move your root declaration up to the "server" block so the server can use the Rails app defined error handling pages when it receives a 5XX, 4XX error.

Or add error_page directives to the location block where passenger is being used so the error handlers can resolve the public/5xx.html in the Rails app public directory when needed.

If your app is not serving up the page and nginx has no visibility to the static page then it can't serve the page you want.

Nord answered 16/3, 2011 at 19:18 Comment(2)
Looks nearly to my problem, but didn't help. Please see updated nginx.conf.Alcibiades
Do you have a 500.html and 404.html in your rails "public" directory?Nord
E
5

To get this working in Rails 3 you'll have to do the following:

First, create your 404 and 500 error pages. I put mine in app/views/errors/404.html.erb and app/views/errors/500.html.erb.

Second, add the following to application_controller.rb:

unless Rails.application.config.consider_all_requests_local
  rescue_from Exception, :with => :render_error
  rescue_from ActiveRecord::RecordNotFound, :with => :render_not_found
  rescue_from AbstractController::ActionNotFound, :with => :render_not_found
  rescue_from ActionController::RoutingError, :with => :render_not_found
  rescue_from ActionController::UnknownController, :with => :render_not_found
  rescue_from ActionController::UnknownAction, :with => :render_not_found
end

def render_error exception
  Rails.logger.error(exception)
  render :template => "/errors/500.haml", :status => 500
end

def render_not_found exception
  Rails.logger.error(exception)
  render :template => "/errors/404.haml", :status => 404
end

Finally, make your production.rb not consider all requests local:

config.consider_all_requests_local = false

P.S: Keep in mind that when a complete routing error happens - i.e when there is absolutely no route match, not just an ActiveRecord NotFound error, the public/404.html will get displayed, so it's good to have that in place. I usually just re-direct it to my errors_controller, which ensures that any 404 errors not caught by the latter mentioned exceptions are still properly redirected to ErrorsController.

<script type="text/javascript">
<!--
window.location = "<%= request.host_with_port %>/errors/404"
//-->
</script>
Emblem answered 16/3, 2011 at 19:16 Comment(10)
This is a way to do it if you want the Rails app to handle it and serve the page. If you want nginx to handle it then edit your block directives. Both will work, just depends on where you want to handle these kinds of errors.Nord
Thanks. Ive seen smth similar here. But this isn't very close to my problem. I'd like to avoid any possibility of showing development errors. One other way to do that for example is to override render_exception method. More native solution was already proposed by Brandon.Alcibiades
There is no chance of rendering development errors if consider_all_requests_local is false. The user will just get a 500 or 404 error page, but no stack trace or internal error message.Emblem
I have config.consider_all_requests_local = false in production.rb but this also doesn't work. Need to say that I checked current environment value (by runnig render :text => Rails.env.inspect) and it properly was set to 'production'.Alcibiades
What part doesn't work? The showing of a stack trace in the browser or the redirecting to a 500/404 error page? What is the result you are getting?Emblem
Something is probably wrong with your implementation. Did you debug the action and check the value of 'Rails.application.config.consider_all_requests_local'? If this is set to false then you won't see this error trace.Emblem
Not sure what should I do to debug that but Rails.application.config.consider_all_requests_local returns 'false'...Alcibiades
That's very odd. I suspect there is something else going on. Maybe a gem that you have installed that's causing this? Do you have goalie installed by any chance? I have Rails 3.0.5 and with consider_all_requests_local set to false I can't see a stack trace in the browser. You are checking this value on your server and during a request, right?Emblem
I've made new clear app (without any gems) and got same effect. I have both development and production(for testing purpose as I newbie in Rails) on same local PC. Development uses mongrel, production deploys to different folder and uses nginx+passenger and available on 'localhost' on 80 port.Alcibiades
In my case it didn't find rescue_fromVenter
B
3

To get errors only in certain controllers

class AdminController < ApplicationController
  rescue_from Exception, :with => :render_simple_error if Rails.env.production?
  def render_simple_error(e)
    render :text => "#{e.message} -- #{e.class}<br/>#{e.backtrace.join("<br/>")}"
  end
end
Briseno answered 27/6, 2011 at 9:27 Comment(0)
N
2

Move your root declaration up to the "server" block so the server can use the Rails app defined error handling pages when it receives a 5XX, 4XX error.

Or add error_page directives to the location block where passenger is being used so the error handlers can resolve the public/5xx.html in the Rails app public directory when needed.

If your app is not serving up the page and nginx has no visibility to the static page then it can't serve the page you want.

Nord answered 16/3, 2011 at 19:18 Comment(2)
Looks nearly to my problem, but didn't help. Please see updated nginx.conf.Alcibiades
Do you have a 500.html and 404.html in your rails "public" directory?Nord
E
1

On apache passenger I used the apache configuration option PassengerFriendlyErrorPages off.

Electron answered 22/3, 2012 at 22:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.