Rails, development env and error pages - development-environment

I've made a simple app and I wanted to test pages for 404, 500 etc. http errors. I've changed config.consider_all_requests_local to false in my enviroments/development.rb but I've still got some problems so I would like to ask you a few questions...
If I type in my bowser something inappropriate like http://localhost:3000/products/dfgdgdgdgfd I still see the old "Unknown action" site. However if I type local ip adress of my computer for ex. http://192.168.1.106:3000/products/dfgdgdgdgfd I can see the 404 error page from public folder. Why is that happening?
I know that if I deploy my little project somewhere than my app will use the production mode and if any error would occure the 404 or 500 page will show up. But what if I want to make those error pages more dynamic ( for ex. rendering error message while using a layout with a list of popular products) or simply redirecting them to the main page?
2.1. The first solution that I found was to use rescue_from method in application controller:
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
.
.
.
private
def render_error exception
Rails.logger.error(exception)
redirect_to root_path
#or
# render :controller=>'errors', :action=>'error_500', :status=>500
end
def render_not_found exception
Rails.logger.error(exception)
redirect_to root_path
#or
# render :controller=>'errors', :action=>'error_404', :status=>404
end
... but that code didn't work at any case.
2.2. The second solution was to place match "*path" , :to => "products#show", :id=>1 (that's the example main page in my silly app) or match "*path" , :to => "errors#error_404", :id=>1 at the end of the routes.rb file. That code works only for typos like http://192.168.1.106:3000/dfgdgdgdgfd because if I try http://192.168.1.106:3000/products/dfgdgdgdgfd (the controller exists but the action is not found) I still got the 404 page.
I've played a bit trying sth like match "*path/*act" , :to => "products#show", :id=>1 or match ":controller(/*act)" , :to => "products#show", :id=>8 but that didn't work either...
2.3. The third solution was to make controller for errors and a file in initializers folder with this code:
# initializers/error_pages.rb
module ActionDispatch
class ShowExceptions
protected
def rescue_action_in_public(exception)
status = status_code(exception).to_s
template = ActionView::Base.new(["#{Rails.root}/app/views"])
if ["404"].include?(status)
file = "/errors/404.html.erb"
else
file = "/errors/500.html.erb"
end
body = template.render(:file => file)
render(status, body)
end
end
end
That was quite useful because it would let me to render dynamic erb files but.. it's not rendering any layout. I've tried to change body = template.render(:file => file) to body = template.render(:partial => file, :layout => "layouts/application") but it was only cousing errors.
I know that I'm doing sth wrong and I belive that there is a working solution for those error pages so I hope that you can help...
Cheers.

In your application controller you need to override this method:
def method_missing(m, *args, &block)
Rails.logger.error(m)
redirect_to :controller=>"errors", :action=>"error_404"
# or render/redirect_to somewhere else
end
and then you have to combine it with this code:
unless Rails.application.config.consider_all_requests_local
rescue_from Exception, :with => :method_missing
rescue_from ActiveRecord::RecordNotFound, :with => :method_missing
rescue_from AbstractController::ActionNotFound, :with => :method_missing
rescue_from ActionController::RoutingError, :with => :method_missing
rescue_from ActionController::UnknownController, :with => :method_missing
rescue_from ActionController::UnknownAction, :with => :method_missing
end

Related

render partial from controller with :layout => !request.xhr? returns missing template?

I cloned and tweak this rails app and I am experiencing some trouble with rendering a partial when on ajax request, in the logs I see that the guilty line is in the registrations_controller.rb (Devise)
class RegistrationsController < Devise::RegistrationsController
def create
build_resource
if resource.save
if resource.active_for_authentication?
sign_in(resource_name, resource)
(render(:partial => 'thankyou', :layout => false) && return) if request.xhr?
respond_with resource, :location => after_sign_up_path_for(resource)
else
resource.update_attribute(:encrypted_password, nil) # make sure there is no password
expire_session_data_after_sign_in!
(render(:partial => 'thankyou', :layout => false) && return) if request.xhr?
respond_with resource, :location => after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
render :partial => 'email_capture', :action => :new, :layout => !request.xhr?**
end
end
protected
def after_inactive_sign_up_path_for(resource)
'/thankyou.html'
end
def after_sign_up_path_for(resource)
redirect_to root_path
end
end
The error message returned is this:
ActionView::MissingTemplate - Missing partial
with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder,
:coffee, :haml]}. Searched in: *
"/Users/Davide/Documents/Jobsite/rails-prelaunch-signup-1click/app/views"
* "/Users/Davide/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/devise_invitable-1.1.8/app/views"
* "/Users/Davide/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/devise-2.2.4/app/views"
Interestingly if I remove the :layout => !=request.xhr? parameter the partial gets found but the page refreshes and the loses all the stylesheets and other assets.
Any idea where should I start looking?
Thanks!
I have also cloned and modified that project, and ran into nearly the same issue. For me, the problem would appear after the second failure of saving a bad email address--but the result was identical.
By using context and information from the following question/answer:
form returned from AJAX request is not recognized as 'remote' when submitted
I was able to make a change that resolved my issue. In _email_capture.html.erb, add :remote => true, to the simple_form_for line. In my case, the whole revised line is:
<%= simple_form_for resource, :as => resource_name, :remote => true, :url => registration_path(resource_name) , :html => {:class => 'form-inline'} do |f| %>
Hope this helps you, too!

Exception notifier - how to display own error pages?

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'

Rails 3 Correctly routing the destroy action for a session

I am refactoring my access_controller into a sessions_controller and can't seem to get my destroy action working properly.
Logging in seems to work fine, but I am unable to log out of a session. Here is the link I have for logging out:
<%= link_to("Logout", :controller => "sessions", :action => 'destroy') %>
routes.rb
resources :sessions
sessions_controller.rb
class SessionsController < ApplicationController
def new
end
def create
...
end
def destroy
session[:user_id] = nil
flash[:notice] = "You are now logged out"
redirect_to root_url
end
end
When I click "Logout" I get redirected to "/sessions/destroy" with a message of "The action 'show' could not be found for SessionsController". The destroy actions seems to want an id, but I don't need to pass in an id, I just want to run the action.
Ah, I found the answer here: http://railscasts.com/episodes/250-authentication-from-scratch
I need to set up my routes as follows:
get "log_out" => "sessions#destroy", :as => "log_out"
get "log_in" => "sessions#new", :as => "log_in"
resources :sessions

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.

Rails 3 rescue_from, with and working with custom modules

I am writing a Rails app that I am wanting to DRY up just a tad bit and instead of calling my custom error class at the top of each controller I need it in, I placed it inside of a Module and just included that module.
Working code (Module):
module ApiException
class EmptyParameter < StandardError
end
end
Working code (Controller):
# include custom error exception classes
include ApiException
rescue_from EmptyParameter, :with => :param_error
# rescure record_not_found with a custom XML response
rescue_from ActiveRecord::RecordNotFound, :with => :active_record_error
def param_error(e)
render :xml => "<error>Malformed URL. Exception: #{e.message}</error>"
end
def active_record_error(e)
render :xml => "<error>No records found. Exception: #{e.message}</error>"
end
Here is my question, using the :with command, how would I call a method inside my custom module?
Something like this: rescue_from EmptyParameter, :with => :EmptParameter.custom_class
You could try something like this:
rescue_from EmptyParameter do |exception|
EmptyParameter.custom_class_method
end