We were unable to load Disqus. If you are a moderator please see our troubleshooting guide.

DS • 11 years ago

Try this to test the 404 page with a bad URL:


require 'test_helper'

feature 'Errors' do
before(:all) do
Rails.application.config.action_dispatch.show_exceptions = true
Rails.application.config.consider_all_requests_local = false
end

after(:all) do
Rails.application.config.action_dispatch.show_exceptions = false
Rails.application.config.consider_all_requests_local = true
end

scenario '404 page' do
visit '/not-a-real-page'
page.status_code.must_equal 404
page.must_have_content '404 - Page Not Found'
end
end

Henrik N • 11 years ago

Oh, excellent. Updated the post and gave you credit. Thank you! Tried with consider_all_requests_local but didn't realize I needed that other one too.

DS • 11 years ago

No problem. Glad it worked :]

Great blog btw. I've learned some new things from you in various posts you've put up. Good stuff!

Henrik N • 11 years ago

Sadly, I just restored the old test code :/ Turns out this worked fine when run as a standalone test, but not as part of a test suite. I suspect once some other test has started a server without that config, a later test can't change it. Maybe due to Spring's preloading?

Glad you like the blog! Thanks for telling me.

helloworld • 11 years ago

I had the same problem -- the spec only passed when run outside of the suite (rails 4.1.5).

action_dispatch.show_exceptions gets copied and cached in Rails.application.env_config, so even if you change Rails.application.config.action_dispatch.show_exceptions in a before block, the value isn't what you expect when it's used in ActionDispatch::DebugExceptions.

My solution was to intercept the env_config method:


method = Rails.application.method(:env_config)
expect(Rails.application).to receive(:env_config).with do
method.call.merge(
'action_dispatch.show_exceptions' => true,
'action_dispatch.show_detailed_exceptions' => false
)
end

I also used "expect_any_instance_of(ActionDispatch::DebugExceptions).to receive(:log_error)" to quiet the printing of the stack trace in specs.

Geremia Taglialatela • 11 years ago

Thanks for sharing this. I suggest to add .(no_args()) after (:env_config).with to prevent an error with latest rspec

lordradler • 10 years ago

updated code snippet:


# errors_spec.rb
context '404' do
before do
method = Rails.application.method(:env_config)
expect(Rails.application).to receive(:env_config).with(no_args()) do
method.call.merge(
'action_dispatch.show_exceptions' => true,
'action_dispatch.show_detailed_exceptions' => false
)
end
end

it 'returns appropriate status code and content' do
visit '/not-a-real-page'
expect(page.status_code).to eql 404
expect(page).to have_content '404 - File Not Found'
end
end
Geremia Taglialatela • 10 years ago
expect(Rails.application).to receive(:env_config).with(no_args()) do
lordradler • 10 years ago

Oh man it's times like this you realize you've been coding for way too many hours and need to go to bed. Duh. Thanks.

Geremia Taglialatela • 10 years ago

you're welcome!

Graham Wagener • 9 years ago

Since RSpec 3.1 you can use and_wrap_original which looks like:


allow(Rails.application).to receive(:env_config).with(no_args()).and_wrap_original do |m, *args|
m.call.merge(
'action_dispatch.show_exceptions' => true,
'action_dispatch.show_detailed_exceptions' => false
)
end
atodorov • 9 years ago

Thanks for sharing. You saved me many hours reading through Rails code. I also had to add 'consider_all_requests_local' => false because I'm testing if my custom error pages actually work.

Rob Lacey • 6 years ago

Just found the solution you posted via another blog. Thanks it was a great help.

Tobias Bohwalli • 11 years ago

Thanks for sharing, any ideas how to test CustomPublicExceptions class with RSpec?

Henrik N • 11 years ago

That class on its own? I'm pretty happy with just an integration test as described in the post.

The CustomPublicExceptions class doesn't do very complex logic, so unit testing it wouldn't add much in my opinion, and would probably be tricky.

Tobias Bohwalli • 11 years ago

Yes, tricky indeed, thats why I asked.

Dean Moyes • 11 years ago

Why don't we just edit the public\assets\404.html page? Is that simpler?

Henrik N • 11 years ago

It's definitely simpler, and there's less risk that some sneaky error takes out your error page, too, but if you want to reuse your Rails layouts or use dynamic content like Rails translations, editing the HTML page is not an option.

Meelana Rawola • 11 years ago

what? if we want to expose error page for 500 error

Fausten van Winklestout • 11 years ago

What's the difference between your approach, and this, seemingly simpler one?
http://easyactiverecord.com...

Along with the routes, all you need to do is tell the app to handle exceptions via the router:

module DevArcadenomadCom
class Application < Rails::Application
config.exceptions_app = self.routes
end
end

Henrik N • 11 years ago

As the intro says:


This is what I did to get a custom 404 error page on Rails 4, without replacing the default 500 and 422 error pages.

There are other solutions where you just use the router as the exceptions app, but then you have to handle those other errors as well.

I don't remember anymore why I wanted a solution with those constraints. I'm sure the simpler solution is better in many cases.

Patricio • 10 years ago

Thanks! Great article. Liked the design of your site, too.

Henrik N • 10 years ago

Thank you, Patricio! :)

Nisha L • 10 years ago

This worked perfectly for me. No edits needed at all. Thanks so much!

travis mathis • 10 years ago

this is a great solution to this.. thanks works like a charm

Andrey Guitaroff • 9 years ago

Thanks so much!!!

SunDi3yansyah • 9 years ago

how, if I want to call the page can not be found on another controller to provide the conditions?

if no_session.nil?
# how to call 404 page
false
else
true
end

Henrik N • 9 years ago

I'm not sure if I understand the question, but maybe this helps: http://thepugautomatic.com/...

SunDi3yansyah • 9 years ago

thxs sir

Anthony Candaele • 9 years ago

this works great, thanks a lot Henrik!

Julia Usanova • 7 years ago

thank you, few years passed and there are a lot of modifications of these basic 2 approaches:
1) with just exceptions_app + routes:

class Application < Rails::Application
config.exceptions_app = self.routes
end

2) similar to your version with errors handling mechanism

But still love yours the most!

Henrik N • 7 years ago

Aw, thank you :)