Exception notifier - how to display own error pages? - ruby-on-rails-3

I use exception_notification gem for handling an errors in an app.
My ApplicationController looks like this:
unless Rails.application.config.consider_all_requests_local
rescue_from Exception,
:with => :render_error
rescue_from ActiveRecord::RecordNotFound,
: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_not_found(exception)
ExceptionNotifier::Notifier
.exception_notification(request.env, exception)
.deliver
render :template => "/errors/404.html.erb",
:layout => 'errors.html.erb'
return
end
def render_error(exception)
ExceptionNotifier::Notifier
.exception_notification(request.env, exception)
.deliver
render :template => "/errors/500.html.erb",
:layout => 'errors.html.erb'
return
end
In /config/enviroments/productions.rg in the end of the file I have:
config.middleware.use ExceptionNotifier,
:email_prefix => "[MY APP| Error Report] ",
:sender_address => %{"MY APP" <err#my-app.com>},
:exception_recipients => 'my_email#gmail.com'
end
when I get the error on the app - eg. Article.find(not-existing-ID), I'll get the standard error page (ERROR 500) from /public/500.html and not from the file specified in application controller... How is that possible? Past hours I tried to find the problem, but I still don't know the issue.

This works for me - from application_controller.rb:
unless Rails.application.config.consider_all_requests_local
rescue_from Exception, with: :render_500
rescue_from ActionController::RoutingError, with: :render_404
rescue_from ActionController::UnknownController, with: :render_404
rescue_from ActionController::UnknownAction, with: :render_404
rescue_from ActiveRecord::RecordNotFound, with: :render_404
end
and
private
def render_404(exception)
ExceptionNotifier::Notifier.exception_notification(request.env, exception,
:data => {:User => current_user.full_name, :Email => current_user.email, :UserID => current_user.id}).deliver
#not_found_path = exception.message
respond_to do |format|
format.html { render template: 'pages/404', layout: 'layouts/application', status: 404 }
format.all { render nothing: true, status: 404}
end
end
def render_500(exception)
ExceptionNotifier::Notifier.exception_notification(request.env, exception,
:data => {:User => current_user.full_name, :Email => current_user.email, :UserID => current_user.id}).deliver
#error = exception
respond_to do |format|
format.html { render template: 'pages/500', layout: 'layouts/application', status: 500 }
format.all { render nothing: true, status: 500}
end
end
Note: I have my custom error pages in /app/views/pages. Called 500.html.haml and 404.html.haml
I also have this in my routes.rb (note a hash after 'pages rather than a forward-slash):
unless Rails.application.config.consider_all_requests_local
match '*not_found', to: 'pages#404'
end
PS. See updated instructions here: http://ramblinglabs.com/blog/2012/01/rails-3-1-adding-custom-404-and-500-error-pages

Hi this works for me try it!
In the application_controller.rb you can add these codes:
if Rails.env.production?
unless Rails.application.config.consider_all_requests_local
rescue_from Exception, with: :render_500
rescue_from ActionController::RoutingError, with: :render_404
rescue_from ActionController::UnknownController, with: :render_404
rescue_from ActionController::UnknownAction, with: :render_404
rescue_from ActiveRecord::RecordNotFound, with: :render_404
end
end
This codes checks if you are running your rails app using production mode and catches different rescue errors.
In the same controller "application_controller.rb" add these codes:
def render_404(exception)
#not_found_path = exception.message
respond_to do |format|
format.html { render template: 'errors/not_found', layout: 'layouts/application', status: 404 }
format.all { render nothing: true, status: 404 }
end
end
def render_500(exception)
logger.info exception.backtrace.join("\n")
respond_to do |format|
format.html { render template: 'errors/internal_server_error', layout: 'layouts/application', status: 500 }
format.all { render nothing: true, status: 500}
end
end
These methods will specify the page you want to display when your app catches an error,
then create a controller named: errors_controller.rb
then in your app/view/errors
create a file named:
internal_server_error.html.erb
and
not_found.html.erb
and in your routes.rb
add these codes:
match '/internal_server_error', :to => 'errors#internal_server_error'
match '/not_found', :to => 'errors#not_found'

Related

Rails: Capture the URL that produced ActionController::RoutingError

I am trying to capture the URL that produced a routing error. My end goal is the change the domain on the URL to check if it exists on our old site (changed the domain) and if so redirect to the old site. Here is what I have do far.
unless Rails.application.config.consider_all_requests_local
rescue_from Exception, with: :render_500
rescue_from ActionController::RoutingError, with: :check_old_site
rescue_from ActionController::UnknownController, with: :render_404
rescue_from ActionController::UnknownAction, with: :render_404
rescue_from ActiveRecord::RecordNotFound, with: :render_404
end
private
def check_old_site(exception)
#Need to edit the URL but I need access to before I can write the code to modify
captured_and_modified_url = ???
case Net::HTTP.get_response(URI.parse(captured_and_modified_url))
when Net::HTTPSuccess then redirect_to captured_and_modified_url
else render_404(exception)
end
end
def render_404(exception)
#not_found_path = exception.message
respond_to do |format|
format.html { render template: 'errors/error_404', layout: 'layouts/application', status: 404 }
format.all { render nothing: true, status: 404 }
end
end
So for this question I just want to get at the URL that got to 404 error. Thanks for any help up front.
Figure this out a while ago. request.path
def check_old_site(exception)
exception_url = "http://old.richarddawkins.net#{request.path}"
case Net::HTTP.get_response(URI.parse(exception_url))
when Net::HTTPSuccess then redirect_to exception_url
else render_404(exception)
end
end

Unable to pass the right parameter to action in RoR

Rails 3.2.2
This code throws an exception ArgumentError missing :action even when I go to the page /my_controller/some_action1
#routes
namespace :my_controller do
get 'some_action1'
get 'some_action2/:some_param1'
end
#Controller
class MyController < ApplicationController
def some_action1
end
def some_action2
#handling the ajax request
respond_to do |format|
format.js
end
end
end
#View /my_controller/some_action1.html.haml
link_to "my_link", {:controller => :my_controller, :action => :some_action2,
:some_param1=>123}, :remote=>true, :id=>"unique_id123"
Your thoughts?
Try to replace your routes with these:
match '/my_controller/some_action1' => "my_controller#some_action1", :via => :get
match '/my_controller/some_action2/:some_param1' => "my_controller#some_action2", :via => :get

RSpec functional test is redirecting to the wrong place

I need some help guys, trying to make this test to pass but with no luck.
describe 'PUT posts/:id' do
describe 'with valid attributes' do
let(:mock_post) { mock_model('Post', title: 'hey! iam a mock!', description: 'a sexy model', location: 'everywhere') }
login_user
it 'should update the object and redirect to the post' do
Post.stub!(:find).with(mock_post.id).and_return(mock_post)
Post.any_instance.should_receive(:update_attributes).with({"these" => "params"}).and_return(true)
response.should redirect_to post_path(mock_post)
put :update, id: mock_post.id, post: { these: 'params' }
end
it 'should have a current_user' do
subject.current_user.should_not be_nil
end
end
For now, I have something like the above test and getting the following error:
1) PostsController PUT posts/:id with valid attributes should update the object and redirect to the post
Failure/Error: response.should redirect_to post_path(mock_post)
Expected response to be a <:redirect>, but was <200>
# ./spec/controllers/posts_controller_spec.rb:200:in `block (4 levels) in <top (required)>'
PostsController:
class PostsController < ApplicationController
load_and_authorize_resource except: [:index, :show]
before_filter :authenticate_user!, except: [:index, :show, :tags]
before_filter :find_post, only: [:show, :edit, :update, :suspend, :suspend_alert]
def update
if #post.update_attributes(params[:post])
flash[:success] = 'Cool.'
redirect_to post_path(#post)
else
render :edit
end
end
protected
def find_post
#post = Post.find(params[:id])
end
end
Also, how should I write the test for the render :edit part?
Your spec never calls the controller action. Try adding:
Post.any_instance.
should_receive(:update_attributes).
with({"these" => "params"})
put :update, :id => "1", :post => {"these" => "params"}
To test the two paths that result from the call to update_attributes, substitute the value in the expectation:
it "should redirect when successful" do
Post.any_instance.
should_receive(:update_attributes).
with({"these" => "params"}).
and_return(true)`
response.should_redirect_to(post_path(#mock_post))
put :update, :id => "1", :post => {"these" => "params"}
end
it "should render the edit page when unsuccessful" do
Post.any_instance.
should_receive(:update_attributes).
with({"these" => "params"}).
and_return(false)`
response.should render_template("edit")
put :update, :id => "1", :post => {"these" => "params"}
end

How can I use rspec to test routes that are being rescued and redirected?

I was trying to write some quick routing tests for a simple api so I wrote:
it "delete" do
delete("/api/notifications/:id").should_not be_routable
end
But I received:
Failure/Error: delete("/api/notifications/:id").should_not be_routable
expected {:delete=>"/api/notifications/:id"} not to be routable, but it routes to {:controller=>"application", :action=>"rescue404", :a=>"api/notifications/:id"}
I quickly realized I was rescuing from 404, so pretty much everything is routable.
unless Rails.env.development?
rescue_from NotFound, :with => :rescue404
rescue_from ActiveRecord::RecordNotFound, :with => :rescue404
rescue_from ActionController::RoutingError, :with => :rescue404
end
def rescue404
respond_to do |format|
format.json { render :text => 'Something went wrong. Record not found or url is incorrect.\n' }
format.xml { render :text => 'Something went wrong. Record not found or url is incorrect.\n' }
format.html { redirect_to root_url, :alert => 'That page does not exist, sorry bro!' }
end
end
That leaves me with this for a test:
it "delete" do
delete("/api/notifications/:id").should route_to("application#rescue404", :a => "api/notifications/:id")
end
Writing this way is error prone to me as I'm constantly getting the ':a =>' wrong. Is there any way I can test if an exception is being rescued?
This works:
it "delete" do
delete("/api/notifications/:id").should raise_error()
end
...but what error should I be checking for? Or should I just leave it at that?
You could change your rescues. Change:
unless Rails.env.development?
to:
if Rails.env.production?
That should leave the test env out of your rescue404 behavior.

No Route matches on Form with nested atributes but not default action

I have a form to update an item called post, but i need a different method than update because there are 2 ways to update the post, i have tried this in a lot of ways but i only get this error
No route matches "/topics/1/posts/35/completed"
the controller:
def completed
#post.download_remote_image
respond_to do |format|
if #post.save
format.html { redirect_to topic_path(#topic), :notice => t('.post_created') }
else
format.html { render :action => :edit }
end
end
end
the view part:
= form_for [#topic, #post], :url => completed_topic_post_path(#topic, #post) do |f|
the routes:
resources :topics do
resources :posts do
get 'complete', :as => :complete
post 'completed', :as => :completed
end
end
Thanks !!
:url => completed_topic_post_path(#topic, #post) needs to be :url => topic_post_completed_path(#topic, #post)