# Default exception doesn't render with correct content type

**URL:** <https://www.ruby-forum.com/t/default-exception-doesnt-render-with-correct-content-type/130532>\
**Category:** Rails\
**Created:** [February 29, 2008, 3:36am UTC](https://www.ruby-forum.com/t/default-exception-doesnt-render-with-correct-content-type/130532 "2008-02-29T03:36:07Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![dusty](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/a183cd/32.png) [@dusty](https://www.ruby-forum.com/u/dusty)\
**Post date:** [February 29, 2008, 3:36am UTC](https://www.ruby-forum.com/t/default-exception-doesnt-render-with-correct-content-type/130532/1 "2008-02-29T03:36:07Z")

</div>

I just noticed something I think is interesting and wanted to see what  
everyone felt about it. Using a quick and dirty scaffold to create a  
resource, I found that if I hit a show url, with an invalid id, it  
will throw an exception in html instead of xml.

Here is how you repeat this.

$ rails testing\_rest  
$ cd testing\_rest  
$ ./script/generate scaffold person name:string  
$ rake db:migrate  
$ ./script/server

From another window

$ curl -i -H “Accept: application/xml” -H “Content-Type: application/  
xml” [http://127.0.0.1:3000/people](http://127.0.0.1:3000/people)

So far, so good. I was returned an empty array in xml

HTTP/1.1 200 OK  
…  
Content-Type: application/xml; charset=utf-8  
…

\<?xml version="1.0" encoding="UTF-8"?\>
* * *

Now, I send over a request for a person that doesn’t exist.

$ curl -i -H “Accept: application/xml” -H “Content-Type: application/  
xml” [http://127.0.0.1:3000/people/1](http://127.0.0.1:3000/people/1)

I get back a full html debug output in html. Yuck!

HTTP/1.1 404 Not Found  
…  
Content-Type: text/html; charset=utf-8  
…

## I chopped the content for readability, its not what matters.

Ok, so I’m in development mode and it will automatically assume I am  
local and spit out the debug. I can handle that, although I still  
don’t think it should be in html.

But, if I run db:migrate again under production and start it up (or  
modify enviroment.rb), and now hit the external IP of my machine  
instead of localhost, I get back the 404 page. Better, but, its still  
coming back in html.

$ curl -i -H “Accept: application/xml” -H “Content-Type: application/  
xml” [http://192.168.1.101:3000/people/1](http://192.168.1.101:3000/people/1)

lication/xml" [http://192.168.247.20:3000/people/1](http://192.168.247.20:3000/people/1)  
HTTP/1.1 404 Not Found  
Connection: close  
Date: Fri, 29 Feb 2008 02:24:02 GMT  
Set-Cookie:  
\_testing\_rest\_session=BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNo  
%250ASGFzaHsABjoKQHVzZWR7AA%253D%253D–  
d1e3f66166f02f6c78f45395f7c0186d7ab9dcd9; path=/  
Status: 404 Not Found  
Cache-Control: no-cache  
Server: Mongrel 1.1.3  
Content-Type: text/html; charset=utf-8  
Content-Length: 947

…

* * *

My question is, shouldn’t this be returning me xml? I do have a  
respond\_to block saying that it should spit back xml. Well, the  
problem is in the way rails handles uncaught exceptions. It doesn’t  
do anything with content-type from what I can see. If there is a  
404.html file in public, it will render it as html. If you don’t have  
a 404.html file, it will simply send back a head with 404 as the  
response. However, it still shows content-type as xml.

So, I guess I have three choices. The first one is to catch that  
exception in my action. The second one is to create a plugin. The  
third is to just not care that I am sending back html to my xml  
clients. I chose the plugin.

What are you all doing? Does it matter that I am sending content-type  
html to an xml client? What about rss, javascript, etc…

BTW - here is my plugin. Nothing special I just add the alternate  
formats I want to the ALT\_FORMATS array. I also have access to a  
template to render instead of a static html file in public. Not sure  
if that gives me anything great, just how I chose to do it at the  
time.

Thoughts??

-Dusty Doris

* * *

```
module MyExceptionHandler
  DEFAULT_CODES = {
    'ActionController::RoutingError' => :not_found,
    'ActionController::UnknownAction' => :not_found,
    'ActiveRecord::RecordNotFound' => :not_found,
    'ActiveRecord::StaleObjectError' => :conflict,
    'ActiveRecord::RecordInvalid' => :unprocessable_entity,
    'ActiveRecord::RecordNotSaved' => :unprocessable_entity,
    'ActionController::MethodNotAllowed' => :method_not_allowed,
    'ActionController::NotImplemented' => :not_implemented,
    'ActionController::InvalidAuthenticityToken'

```

=\> :unprocessable\_entity  
}

```
  ALT_FORMATS = [:xml, :json, :js, :rss, :atom, :text]

  def rescue_action_in_public(exception)
    @exception = exception
    respond_to do |format|
      format.html do
        render :template => "exceptions/#{return_code.to_s}",
               :layout => "exceptions",
               :status => return_code
      end
      ALT_FORMATS.each do |f|
        format.send(f) { head :status => return_code }
      end
    end
  end

  def rescue_action_locally(exception)
    respond_to do |format|
      format.html do
        add_variables_to_assigns
        @template.instance_variable_set("@exception", exception)
        @template.instance_variable_set("@rescues_path",
          File.dirname(rescues_path("stub")))
        @template.send!(:assign_variables_from_controller)
        @template.instance_variable_set("@contents",

```

@template.render\_file(template\_path\_for\_local\_rescue(exception),  
false))  
response.content\_type = Mime::HTML  
render\_for\_file(rescues\_path(“layout”),  
response\_code\_for\_rescue(exception))  
end  
ALT\_FORMATS.each do |f|  
format.send(f) { head :status =\> return\_code }  
end  
end  
end

```
  private
  def return_code
    DEFAULT_CODES[@exception.class.to_s] || :internal_server_error
  end

end

```

With a little

require ‘my\_exception\_handler’  
ActionController::Base.send :include, MyExceptionHandler  
ActionController::Base.consider\_all\_requests\_local = false

---

<div class="post-metadata">

**Author:** ![dusty](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/a183cd/32.png) [@dusty](https://www.ruby-forum.com/u/dusty)\
**Post date:** [February 29, 2008, 3:52am UTC](https://www.ruby-forum.com/t/default-exception-doesnt-render-with-correct-content-type/130532/2 "2008-02-29T03:52:37Z")

</div>

dusty wrote:

> require ‘my\_exception\_handler’  
> ActionController::Base.send :include, MyExceptionHandler  
> ActionController::Base.consider\_all\_requests\_local = false

something like the following will also work…

class Application \< ActionController::Base  
around\_filter :catch\_exceptions

def catch\_exceptions  
begin  
yield  
rescue Exception =\> e  
render :xml =\> e.message, :status =\> 500  
end  
end

end

---

<div class="post-metadata">

**Author:** ![dusty](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/a183cd/32.png) [@dusty](https://www.ruby-forum.com/u/dusty)\
**Post date:** [February 29, 2008, 4:25am UTC](https://www.ruby-forum.com/t/default-exception-doesnt-render-with-correct-content-type/130532/3 "2008-02-29T04:25:23Z")

</div>

Thanks for the reply. That would be much easier. The filters are  
nice, unfortunately, it doesn’t catch things like  
ActionController::RoutingErrors. At least its not for me. It does  
catch things like notfound errors within an action though.

---

<div class="post-metadata">

**Author:** ![dusty](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/a183cd/32.png) [@dusty](https://www.ruby-forum.com/u/dusty)\
**Post date:** [February 29, 2008, 4:35am UTC](https://www.ruby-forum.com/t/default-exception-doesnt-render-with-correct-content-type/130532/4 "2008-02-29T04:35:11Z")

</div>

dusty wrote:

> Thanks for the reply. That would be much easier. The filters are  
> nice, unfortunately, it doesn’t catch things like  
> ActionController::RoutingErrors. At least its not for me. It does  
> catch things like notfound errors within an action though.

You are right, it won’t catch routing errors as they are thrown before  
the surround\_filters get a chance to party ☹

ilan
