#53 Handling Exceptions (revised)
By default, Rails will render a static error file when an exception occurs in production. Here you will learn how to fully customize this behavior and render dynamic error pages.
- Download:
- source code
- mp4
- m4v
- webm
- ogv
In order to test the dynamic generation of error pages, you need to be in production environment, which is incompatible with running your entire test suite, normally in test environment.
Similarly hacking the config.consider_all_requests_local parameter may is not viable except as a short-term hack to see dynamic error pages operating in dev or test environment.
So I found it best to move the ErrorsController and associated views into a Rails engine... that way it can have a test suite of its own, running the tests in production environment.
C'est très sympathique de donner cet espace où je peux parler de mon site Internet dédié à la maternité et à différentes thématiques féminines, surtout en rapport avec les mamans et leur enfant.
Si vous êtes une maman souhaitant participer rendez-vous sur mon site
Really cool stuff
@laylester, could you please put out a sample/example on Github?
Thanks.
Bharat
Yeah it would be cool please
@Bharat Ruparal
https://github.com/lazylester/error_pages_engine
This is certainly an area of my apps that needs some TLC. Thanks!
Nice episode, but it would be beneficial to add something like
response.status = request.path[1..-1]
to make the status code carry over (if anyone knows of a nicer way to do this, speak up).Otherwise, the error pages will all have a status of
200 OK
since the error controller itself responded normally.Indeed - it may be not needed for HTML version, but definitely JSON API would benefit from having the right status code:
Yeah, web APIs are (or should be) sticklers for proper status codes, but any ol' HTML browser can infer a lot from the status code too. Whether or not to use the URL when auto-completing an address for the user, for instance. It's annoying to have the browser remember a URL for an error page, only because that page accidentally sent a
200 OK
I found a replacement for
request.path[1..-1]
posted by Jeroen Rosenberg:Has anyone found a good way to test this with RSpec?
I use RSpec to test this in a standalone engine. See https://github.com/lazylester/error_pages_engine. This way I can run the tests in a production environment just for testing the engine, and my application's test suite runs as usual in test environment.
Also since this functionality comprises a controller and views, is unrelated to the application's main functionality, and may be included in multiple apps, it seems to be a perfect place to use the Rails engine concept.
Did you find a good way to do this? For example, using this episode, ActiveRecord::RecordNotFound errors ultimately redirect to the errors/404 view. However, I have the following in one of my tests (Item belongs_to List):
However, the test fails with the following:
So the controller is working properly in requiring a list, but the test fails because it doesn't take into account the custom exception handling which should send the user to the 404. Hmm...
The answer is here: http://stackoverflow.com/questions/13996259/testing-error-pages-in-rails-with-rspec-capybara
This doesn't work for controller specs :( Any ideas on how to get this working for controller specs?
Did you get this working? I am seeing the same issue.
Thanks Ryan, exactly the right episode at the right time :)
One note on using curl. It seem easy and nice to simply generate the static pages via "curl http://localhost:3000/errors/404 > public/404.html".
But beware that you generate them under the development environment but serves them in production. At least when they are checked in and deployed to production.
Your pages may contain stuff that should only be visible in development mode and not on staging or production.
So you may need to run the curl command on production to get the correct pages. That can be done manually after each deployment but that's cumbersome.
One can add a capistrano recipes that runs after deploy:restart (when the app is up using the maybe new layout). But then you great the pages whenever you restart the app.
And with static pages you cannot serve different pages for different context. For example a signed in user will get a 404 page without his user menu (preferences, account, ...) and
maybe without the logout button. That can be ok in your case but should be considered.
If you are fine with static pages you may generate them outside the controller via a rake tasks and run that task on every deployment via after "deploy:create_symlink", "deploy:error_pages:create"
We tried this but now using your solution via the ErrorsController.
Thanks!
Nice episode.
I just had to handle a situation where I had to disply a custom error message on a ActiveRecord::RecordNotFound Exception for a specific controller.
Although this episode I can't figure out how to set a custom error message.
This doesn't work with airbrake :s
Do anyone know a solution to this?
+1 this is a bummer
You can just manually send the Airbrake using Airbrake.notify_or_ignore(...)
Thank you for awesome screencast. I got inspired and wrote little more enhanced version of this (for example fallback to generic error message layout, and hiding 500 error messages in production): https://github.com/sheerun/rails4-bootstrap/commit/5c2df5a108ad204bc407183b959bb355ff5ed53d
if anyone needs a rake task for generating public pages you can use mine https://github.com/equivalent/forgotten_software/blob/master/2013-10-custom_error_pages/lib/tasks/generate_error_pages.rake
thanks
Great screencast as always! Some reason, when trying to go directly to the url, http://localhost:3000/errors/404
Rails wants to look in errors/errors folder in the views.
ActionView::MissingTemplate at /errors/404
Missing template errors/errors/404, application/errors/404 with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :coffee, :haml]}.
had to change the controller to
format.html { render request.path[1..-1] }
It appears that config.exceptions_app = self.routes no longer works in Rails 4. I implemented custom error pages using this when my application was 3.2.13. However when I rewrote the application in Rails 4.0.0 it completely ignored my custom error pages. Thankfully I could move them to the public folder (no ruby code) even with localization. All I did was to create separate views for each locale (i.e. 404.en.html, 404.fr.html) in the pubic folder. No other changes were needed. When I get a 404 error for locale en the English error page displays. When I get a 404 error for locale fr the French error page displays. Maybe there is a way to use html.erb files in the public folder to access some of the information in this wonderful RailsCast episode.
I am encountering the same problem. It's a shame that this functionality is broken (or removed) from rails 4.
Tried in Rails 4, works fine. Except calling directly to
errors/404
(for using the curl stuff). However Mike Henke pointed to the correct solution, at least in Rails 4 I had to remove theaction:
part. After that it worked fine. Including the status passing it would be:Also, just using the dynamic pages would result in my feature specs into a
ActionView::MissingTemplate
error. Even withconfig.consider_all_requests_local = false
in thetest.rb
within the environments folder.The only thing that helped me so far was to create static error pages using the (now working) curl command.
I noticed that in 404 cases the ExceptionWrapper somehow returned 500 (not sure why). When really an exception occured, it would however render a 404 instead of a 500.
In stead of my previous comment, I have used:
Also, I figured that simply creating static error pages (even from PROD environment) is not sufficient in Rails 4. The whole reason I am using dynamic pages is because the assets no longer are offered in a non-digest way. Therefor I cannot generate static pages and commit them, as the digest will change per deploy on prod (precompiling assets everytime). A github issue (https://github.com/rails/sprockets-rails/issues/49) has been made a while back about this.
It would be nice if Ryan could elaborate/update this screencast about this issue.
Really USEFULL Thanks Ryan
I'm sure this is simple, but I can't find a way to manually send someone to a 404 (using the middleware approach). For example, I want to "hide" private widgets if the widget author is not the current user:
I tried
render text: "Not found", status: 404
but that does exactly that, just renders the text instead of handling it through the errors controller. I also triedrender status: 404
, but that still shows the record (albeit with a 404 status in the web inspector).Thanks, @Xavar. I had been using the following:
But because I wasn't calling
.new('Not Found')
on it, I was getting a 500 (missing arguments) instead of the expected 404. So as a lesson, you can use either of the following to trigger a 404:Using status respond to the error is better for others system knows what is happeing
This approach is used on our app and currently we are having troubles whenever a gem we are using raises an error - instead of an error message we are getting nginx Bad Gateway pages and nothing in the log and the ErrorsController show action does not get run at all (Could be for another reason and not due to this approach at all - not sure - just seems likely)
Bad Gateway error was due to Rubinius and Mail gem not working together - not related to this approach - sorry.
good job
Now I finally understand, thanks!
I have investigated your stunning post. This is a unimaginable occupation. I have respected the experience of secluding your post first time
I like your all post. You have done really good work. I appreciate your working style at the end just my request is please share with us some more great post... .
I like your all post. You have done really good work. I appreciate your working style at the end just my request is please share with us some more great post... .
Thanks for the tips and guide. It is very useful tips.
I really wanted to send a small word to say thanks to you for the fantastic points you are writing on this site.
Great post & Best website
I didn't realize I was still considered a new user...
Thanks so much for this wonderful and great website as well as this post.
Good
gc-spiele.de
cool blog
Gracias
Superb post.
Its really awesome
thxks
lovely
ok thanks
Thank you for your work on the blog! You're doing a good job!
penyebab sipilis itu apa
cara menyembuhkan sipilis bagaimaana ya