I have setup custom error pages in my rails app.
application.rb
config.exceptions_app = self.routes
routes.rb
get '404', to: 'application#page_not_found'
get '422', to: 'application#server_error'
get '500', to: 'application#server_error'
application_controller.rb
def page_not_found
respond_to do |format|
format.html { render template: 'errors/not_found_error', layout: 'layouts/application', status: 404 }
format.all { render nothing: true, status: 404 }
end
end
def server_error
respond_to do |format|
format.html { render template: 'errors/internal_server_error', layout: 'layouts/error', status: 500 }
format.all { render nothing: true, status: 500}
end
end
My custom 500 error page shows up fine when I do a GET request that throws the error but when I submit a form that triggers a NoMethodError, so a PUT request, I just get a blank page.
Any ideas why the 500 error page displays correctly for a GET request but not for a PUT request?
I tried changing the server_error method to
def server_error
render template: 'errors/internal_server_error', layout: 'layouts/error', status: 500
end
but this didn't seem to help.
Let me know if I can provide more code, I'm not sure how to troubleshoot this.
use match and via on your routes.rb to route all types of HTTP requests to custom error actions
# error routes
match '/404' => 'application#page_not_found', :via => :all
match '/422' => 'application#unprocessable_entity', :via => :all
match '/500' => 'application#server_error', :via => :all
Related
I am fixing some tests and the first line of the following test gives me this error
ActionController::MissingExactTemplate: EventsController#index is missing a template for request formats: text/html.
test "#index should respond to the correct format" do
get :index, params: {id: #event.id, format: :html} #<-- this line causes problems
assert_response :success
get :index, params: {id: #event.id, format: :json}
assert_response :success
end
I believe the error refers to the following method in the controllers.
def index
#events = Event.upcoming.recent
respond_to do |format|
format.html # index.html.erb
format.json { render json: #events }
end
end
I am starting to consider that the line is useless but I am still unsure.
If you make a json request, then format.json { render json: #events } will render the response.
If you make a HTML request, then format.html will look for a html file in app/views/event/index.html.erb
So, you need to create a file in the above location.
I am facing the routing error if the route is not match. I want to redirect the page to 404 static page if the route not match.
I used some references but it's not working.
The following error is displayed when No route matches.
No route matches [GET] "/userss"
Rails.root: D:/Ruby/Assignment/Library
At the end of your routes.rb file write
get '*path' => redirect('your path of static page')
Add these lines in your application_controller.rb
rescue_from ActionController::RoutingError, with: :render_404
private
def render_404
respond_to do |format|
format.html { render "#{Rails.root}/public/404.html", status: 404 }
format.json { render json: { status: 404, message: 'Page Not Found' } }
end
end
If we request a bogus image file, Rails generates an internal 500 server error instead of a 404. See the log below.
Here is the line in routes.rb that catches 404s:
# Catches all 404 errors and redirects
match '*url' => 'default#error_404'
Other unknown URLs are handled correctly with 404s. What is different for image files and URLs with file extensions?
Started GET "/images/doesnotexistyo.png" for 71.198.44.101 at 2013-03-08 07:59:24 +0300
Processing by DefaultController#error_404 as PNG
Parameters: {"url"=>"images/doesnotexistyo"}
Completed 500 Internal Server Error in 1ms
ActionView::MissingTemplate (Missing template default/error_404, application/error_404 with {:locale=>[:en], :formats=>[:png], :handlers=>[:erb, :builder]}. Searched in:
* "/home/prod/Prod/app/views"
The problem is that the error_404 method inside the Default controller can't handle requests in png format. When you ask for say, a JSON response, you could build an URL similar to:
/controller/action.json
And inside the action you would have something like
def action
respond_to do |format|
format.html # Renders the default view
format.json { render :json => #model }
format.xml { render :xml => #model }
end
end
As you can see, it's specified how to handle a JSON and an XML request, but since there's no format.png, the action can't handle the .png format. Add this:
format.png # Handle the request here...
Hope it helps :)
Edit
Add this to redirect to your 404 handler:
def error_404
respond_to do |format|
format.html
format.png { redirect_to :controller => 'default', :action => 'error_404' }
end
end
Cheers :)
Edit2
Use this code to catch all kinds of requests:
def error_404
respond_to do |format|
format.html { render :not_found_view }
format.all { redirect_to controller: 'default', action: 'error_404' }
end
end
Replace :not_found_view with your 404 page. This will render the 404 page for html requests, and redirect to self (with html format) for any other kind of request.
Hope it helps :)
What is DefaultController? That controller is dealing with the 404, instead of Rails default response:
ActionController::RoutingError (No route matches [GET] "/images/doesnotexistyo.png"):
So find out this controller, error_404 is being executed and no template default/error_404 was found, hence the 500 error.
You probably have a code similar to this somewhere in your code:
rescue_from ActiveRecord::RecordNotFound, :with => :error_404
Maybe not for you, but since I do some final checks for pages dynamically in my controllers, I just follow all my 404'ing with one to handle non-html files:
format.all { render :status => 404, :nothing => true }
I have a route that I need to call like so:
/images/get_subcollections.json?id=1234
I have this in my routes file:
resources :images do
collection do
get 'get_subcollections'
end
end
I have this in my controller:
def get_subcollections
collection = Collection.find(params[:id])
respond_to do |format|
format.json { render :layout => false, :json => collection.to_json(:methods=>:get_subcollections) }
end
end
The app just sits there when I call the URL. The request doesn't get logged or anything. Any ideas? Thanks!
Have you inspected the response using firebug or chrome's dev tools? Is it just that layout: false is stopping you seeing anything?
I am having a normal HTML frontend and a JSON API in my Rails App. Now, if someone calls /api/not_existent_method.json it returns the default HTML 404 page. Is there any way to change this to something like {"error": "not_found"} while leaving the original 404 page for the HTML frontend intact?
A friend pointed me towards a elegant solution that does not only handle 404 but also 500 errors. In fact, it handles every error. The key is, that every error generates an exception that propagates upwards through the stack of rack middlewares until it is handled by one of them. If you are interested in learning more, you can watch this excellent screencast. Rails has it own handlers for exceptions, but you can override them by the less documented exceptions_app config option. Now, you can write your own middleware or you can route the error back into rails, like this:
# In your config/application.rb
config.exceptions_app = self.routes
Then you just have to match these routes in your config/routes.rb:
get "/404" => "errors#not_found"
get "/500" => "errors#exception"
And then you just create a controller for handling this.
class ErrorsController < ActionController::Base
def not_found
if env["REQUEST_PATH"] =~ /^\/api/
render :json => {:error => "not-found"}.to_json, :status => 404
else
render :text => "404 Not found", :status => 404 # You can render your own template here
end
end
def exception
if env["REQUEST_PATH"] =~ /^\/api/
render :json => {:error => "internal-server-error"}.to_json, :status => 500
else
render :text => "500 Internal Server Error", :status => 500 # You can render your own template here
end
end
end
One last thing to add: In the development environment, rails usally does not render the 404 or 500 pages but prints a backtrace instead. If you want to see your ErrorsController in action in development mode, then disable the backtrace stuff in your config/enviroments/development.rb file.
config.consider_all_requests_local = false
I like to create a separate API controller that sets the format (json) and api-specific methods:
class ApiController < ApplicationController
respond_to :json
rescue_from ActiveRecord::RecordNotFound, with: :not_found
# Use Mongoid::Errors::DocumentNotFound with mongoid
def not_found
respond_with '{"error": "not_found"}', status: :not_found
end
end
RSpec test:
it 'should return 404' do
get "/api/route/specific/to/your/app/", format: :json
expect(response.status).to eq(404)
end
Sure, it will look something like this:
class ApplicationController < ActionController::Base
rescue_from NotFoundException, :with => :not_found
...
def not_found
respond_to do |format|
format.html { render :file => File.join(Rails.root, 'public', '404.html') }
format.json { render :text => '{"error": "not_found"}' }
end
end
end
NotFoundException is not the real name of the exception. It will vary with the Rails version and the exact behavior you want. Pretty easy to find with a Google search.
Try to put at the end of your routes.rb:
match '*foo', :format => true, :constraints => {:format => :json}, :to => lambda {|env| [404, {}, ['{"error": "not_found"}']] }