4

I have a Rails 3.0 app (working on a 3.2 upgrade) and whenever someone requests a template that doesn't exist it gives a 500 error in production. For instance mysite.com/blog_posts/532 sends the post with ID 532 back as HTML no problem, but if for some reason mysite.com/blog_posts/532.txt is requested, the app raises a 500 ActionView::MissingTemplate error.

This shouldn't happen, because the template shouldn't be there in the first place. It should more properly be a 404 error, or perhaps just show the HTML template.

How can I make the app either show a 404 error for all missing-template errors, or show the default HTML template instead of giving a 500?

Log:

Started GET "/blog_posts/73.txt" for 127.0.0.1 at 2013-05-20 21:22:51 -0400
  Processing by BlogPostsController#show as TEXT
  Parameters: {"id"=>"73"}
  PK and serial sequence (2.0ms)   SELECT attr.attname, seq.relname
 FROM pg_class seq,
 pg_attribute attr,
 pg_depend dep,
 pg_namespace name,
 pg_constraint cons
 WHERE seq.oid = dep.objid
 AND seq.relkind = 'S'
 AND attr.attrelid = dep.refobjid
 AND attr.attnum = dep.refobjsubid
 AND attr.attrelid = cons.conrelid
 AND attr.attnum = cons.conkey[1]
 AND cons.contype = 'p'
 AND dep.refobjid = '"blog_posts_blog_tags"'::regclass
  PK and custom sequence (1.0ms)   SELECT attr.attname,
 CASE
 WHEN split_part(def.adsrc, '''', 2) ~ '.' THEN
 substr(split_part(def.adsrc, '''', 2),
 strpos(split_part(def.adsrc, '''', 2), '.')+1)
 ELSE split_part(def.adsrc, '''', 2)
 END
 FROM pg_class t
 JOIN pg_attribute attr ON (t.oid = attrelid)
 JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
 JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
 WHERE t.oid = '"blog_posts_blog_tags"'::regclass
 AND cons.contype = 'p'
 AND def.adsrc ~* 'nextval'
  BlogPost Load (0.0ms)  SELECT "blog_posts".* FROM "blog_posts" WHERE "blog_posts"."id" = '73' LIMIT 1
  SQL (0.0ms)   SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull
 FROM pg_attribute a LEFT JOIN pg_attrdef d
 ON a.attrelid = d.adrelid AND a.attnum = d.adnum
 WHERE a.attrelid = '"blog_posts"'::regclass
 AND a.attnum > 0 AND NOT a.attisdropped
 ORDER BY a.attnum
Completed 500 Internal Server Error in 59ms
  User Load (1.0ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
  SQL (1.0ms)   SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull
 FROM pg_attribute a LEFT JOIN pg_attrdef d
 ON a.attrelid = d.adrelid AND a.attnum = d.adnum
 WHERE a.attrelid = '"users"'::regclass
 AND a.attnum > 0 AND NOT a.attisdropped
 ORDER BY a.attnum

ActionView::MissingTemplate (Missing template blog_posts/show with {:handlers=>[:erb, :rjs, :builder, :rhtml, :rxml], :formats=>[:text], :lo
cale=>[:en, :en]} in view paths "C:/Rails/myapp/app/views", "C:/Ruby/lib/ruby/gems/1.9.1/gems/devise-1.5.4/app/views"):


Rendered C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_dispatch/middleware/templates/rescues/missing_template.erb within res
cues/layout (1.0ms)

Updated log, with trace:

Started GET "/blog_posts/73.txt" for 127.0.0.1 at 2013-05-20 22:14:28 -0400
  Processing by BlogPostsController#show as TEXT
  Parameters: {"id"=>"73"}
  PK and serial sequence (2.0ms)   SELECT attr.attname, seq.relname
 FROM pg_class seq,
 pg_attribute attr,
 pg_depend dep,
 pg_namespace name,
 pg_constraint cons
 WHERE seq.oid = dep.objid
 AND seq.relkind = 'S'
 AND attr.attrelid = dep.refobjid
 AND attr.attnum = dep.refobjsubid
 AND attr.attrelid = cons.conrelid
 AND attr.attnum = cons.conkey[1]
 AND cons.contype = 'p'
 AND dep.refobjid = '"blog_posts_blog_tags"'::regclass
  PK and custom sequence (1.0ms)   SELECT attr.attname,
 CASE
 WHEN split_part(def.adsrc, '''', 2) ~ '.' THEN
 substr(split_part(def.adsrc, '''', 2),
 strpos(split_part(def.adsrc, '''', 2), '.')+1)
 ELSE split_part(def.adsrc, '''', 2)
 END
 FROM pg_class t
 JOIN pg_attribute attr ON (t.oid = attrelid)
 JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
 JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
 WHERE t.oid = '"blog_posts_blog_tags"'::regclass
 AND cons.contype = 'p'
 AND def.adsrc ~* 'nextval'
  BlogPost Load (0.0ms)  SELECT "blog_posts".* FROM "blog_posts" WHERE "blog_posts"."id" = '73' LIMIT 1
  SQL (0.0ms)   SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull
 FROM pg_attribute a LEFT JOIN pg_attrdef d
 ON a.attrelid = d.adrelid AND a.attnum = d.adnum
 WHERE a.attrelid = '"blog_posts"'::regclass
 AND a.attnum > 0 AND NOT a.attisdropped
 ORDER BY a.attnum
--------------------------------------------------------------------------------
exception: Missing template blog_posts/show with {:handlers=>[:erb, :rjs, :builder, :rhtml, :rxml], :formats=>[:text], :locale=>[:en, :en]} in view paths "C:/Rails/myapp/app/views", "C:/Ruby/lib/ruby/gems/1.9.1/gems/devise-1.5.4/app/views"
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_view/paths.rb:15:in `find'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_view/lookup_context.rb:81:in `find'
C:in `find_template'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_view/render/rendering.rb:46:in `_determine_template'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_view/render/rendering.rb:24:in `render'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/abstract_controller/rendering.rb:115:in `_render_template'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/abstract_controller/rendering.rb:109:in `render_to_body'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_controller/metal/renderers.rb:47:in `render_to_body'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_controller/metal/compatibility.rb:55:in `render_to_body'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/abstract_controller/rendering.rb:102:in `render_to_string'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/abstract_controller/rendering.rb:93:in `render'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_controller/metal/rendering.rb:17:in `render'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_controller/metal/instrumentation.rb:40:in `block (2 levels) in render'
C:/Ruby/lib/ruby/gems/1.9.1/gems/activesupport-3.0.20/lib/active_support/core_ext/benchmark.rb:5:in `block in ms'
C:/Ruby/lib/ruby/1.9.1/benchmark.rb:295:in `realtime'
C:/Ruby/lib/ruby/gems/1.9.1/gems/activesupport-3.0.20/lib/active_support/core_ext/benchmark.rb:5:in `ms'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_controller/metal/instrumentation.rb:40:in `block in render'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_controller/metal/instrumentation.rb:78:in `cleanup_view_runtime'
C:/Ruby/lib/ruby/gems/1.9.1/gems/activerecord-3.0.20/lib/active_record/railties/controller_runtime.rb:15:in `cleanup_view_runtime'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_controller/metal/instrumentation.rb:39:in `render'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_controller/metal/implicit_render.rb:10:in `default_render'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_controller/metal/implicit_render.rb:5:in `send_action'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/abstract_controller/base.rb:150:in `process_action'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_controller/metal/rendering.rb:11:in `process_action'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/abstract_controller/callbacks.rb:18:in `block in process_action'
C:/Ruby/lib/ruby/gems/1.9.1/gems/activesupport-3.0.20/lib/active_support/callbacks.rb:436:in `_run__326851374__process_action__856302785__callbacks'
C:/Ruby/lib/ruby/gems/1.9.1/gems/activesupport-3.0.20/lib/active_support/callbacks.rb:410:in `_run_process_action_callbacks'
C:/Ruby/lib/ruby/gems/1.9.1/gems/activesupport-3.0.20/lib/active_support/callbacks.rb:94:in `run_callbacks'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/abstract_controller/callbacks.rb:17:in `process_action'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_controller/metal/rescue.rb:17:in `process_action'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_controller/metal/instrumentation.rb:30:in `block in process_action'
C:/Ruby/lib/ruby/gems/1.9.1/gems/activesupport-3.0.20/lib/active_support/notifications.rb:52:in `block in instrument'
C:/Ruby/lib/ruby/gems/1.9.1/gems/activesupport-3.0.20/lib/active_support/notifications/instrumenter.rb:21:in `instrument'
C:/Ruby/lib/ruby/gems/1.9.1/gems/activesupport-3.0.20/lib/active_support/notifications.rb:52:in `instrument'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_controller/metal/instrumentation.rb:29:in `process_action'
C:/Ruby/lib/ruby/gems/1.9.1/gems/newrelic_rpm-3.6.2.96/lib/new_relic/agent/instrumentation/rails3/action_controller.rb:38:in `block in process_action'
C:/Ruby/lib/ruby/gems/1.9.1/gems/newrelic_rpm-3.6.2.96/lib/new_relic/agent/instrumentation/controller_instrumentation.rb:318:in `perform_action_with_newrelic_trace'
C:/Ruby/lib/ruby/gems/1.9.1/gems/newrelic_rpm-3.6.2.96/lib/new_relic/agent/instrumentation/rails3/action_controller.rb:37:in `process_action'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/abstract_controller/base.rb:119:in `process'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/abstract_controller/rendering.rb:41:in `process'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_controller/metal.rb:138:in `dispatch'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_controller/metal/rack_delegation.rb:14:in `dispatch'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_controller/metal.rb:178:in `block in action'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_dispatch/routing/route_set.rb:68:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_dispatch/routing/route_set.rb:68:in `dispatch'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_dispatch/routing/route_set.rb:33:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/rack-mount-0.6.14/lib/rack/mount/route_set.rb:148:in `block in call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/rack-mount-0.6.14/lib/rack/mount/code_generation.rb:93:in `block in recognize'
C:/Ruby/lib/ruby/gems/1.9.1/gems/rack-mount-0.6.14/lib/rack/mount/code_generation.rb:89:in `optimized_each'
C:/Ruby/lib/ruby/gems/1.9.1/gems/rack-mount-0.6.14/lib/rack/mount/code_generation.rb:92:in `recognize'
C:/Ruby/lib/ruby/gems/1.9.1/gems/rack-mount-0.6.14/lib/rack/mount/route_set.rb:139:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_dispatch/routing/route_set.rb:499:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/newrelic_rpm-3.6.2.96/lib/new_relic/rack/error_collector.rb:12:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/newrelic_rpm-3.6.2.96/lib/new_relic/rack/agent_hooks.rb:18:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/newrelic_rpm-3.6.2.96/lib/new_relic/rack/developer_mode.rb:28:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/warden-1.2.1/lib/warden/manager.rb:35:in `block in call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/warden-1.2.1/lib/warden/manager.rb:34:in `catch'
C:/Ruby/lib/ruby/gems/1.9.1/gems/warden-1.2.1/lib/warden/manager.rb:34:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_dispatch/middleware/best_standards_support.rb:17:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_dispatch/middleware/head.rb:14:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/rack-1.2.7/lib/rack/methodoverride.rb:24:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_dispatch/middleware/params_parser.rb:21:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_dispatch/middleware/flash.rb:182:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_dispatch/middleware/session/abstract_store.rb:149:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_dispatch/middleware/cookies.rb:302:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/activerecord-3.0.20/lib/active_record/query_cache.rb:32:in `block in call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/activerecord-3.0.20/lib/active_record/connection_adapters/abstract/query_cache.rb:28:in `cache'
C:/Ruby/lib/ruby/gems/1.9.1/gems/activerecord-3.0.20/lib/active_record/query_cache.rb:12:in `cache'
C:/Ruby/lib/ruby/gems/1.9.1/gems/activerecord-3.0.20/lib/active_record/query_cache.rb:31:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/activerecord-3.0.20/lib/active_record/connection_adapters/abstract/connection_pool.rb:354:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_dispatch/middleware/callbacks.rb:46:in `block in call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/activesupport-3.0.20/lib/active_support/callbacks.rb:416:in `_run_call_callbacks'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_dispatch/middleware/callbacks.rb:44:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/rack-1.2.7/lib/rack/sendfile.rb:106:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_dispatch/middleware/remote_ip.rb:48:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_dispatch/middleware/show_exceptions.rb:47:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/railties-3.0.20/lib/rails/rack/logger.rb:13:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/rack-1.2.7/lib/rack/runtime.rb:17:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/activesupport-3.0.20/lib/active_support/cache/strategy/local_cache.rb:72:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/rack-1.2.7/lib/rack/lock.rb:13:in `block in call'
<internal:prelude>:10:in `synchronize'
C:/Ruby/lib/ruby/gems/1.9.1/gems/rack-1.2.7/lib/rack/lock.rb:13:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/actionpack-3.0.20/lib/action_dispatch/middleware/static.rb:30:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/airbrake-3.1.4/lib/airbrake/rack.rb:41:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/airbrake-3.1.4/lib/airbrake/user_informer.rb:12:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/railties-3.0.20/lib/rails/application.rb:168:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/railties-3.0.20/lib/rails/application.rb:77:in `method_missing'
C:/Ruby/lib/ruby/gems/1.9.1/gems/railties-3.0.20/lib/rails/rack/log_tailer.rb:14:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/rack-1.2.7/lib/rack/content_length.rb:13:in `call'
C:/Ruby/lib/ruby/gems/1.9.1/gems/rack-1.2.7/lib/rack/handler/webrick.rb:52:in `service'
C:/Ruby/lib/ruby/1.9.1/webrick/httpserver.rb:138:in `service'
C:/Ruby/lib/ruby/1.9.1/webrick/httpserver.rb:94:in `run'
C:/Ruby/lib/ruby/1.9.1/webrick/server.rb:191:in `block in start_thread'
--------------------------------------------------------------------------------
Completed 200 OK in 59ms
[2013-05-20 22:14:28] WARN  Could not determine content-length of response body. Set content-length of the response or set Response#chunked
= true
John
  • 3,430
  • 2
  • 31
  • 44
  • Hi John, can you please post the log for your request? I've just tried with an app of mine and I get a 406 not acceptable because .txt is not an acceptable request. If you get a 500 there should be a reason. – Idavod May 21 '13 at 01:21
  • I just updated the question with the log. I wonder what's different with our respective apps? I like Doon's answer below, but I'm very interested to understand the different behavior. – John May 21 '13 at 01:27
  • You need to isolate the problem. I suggest you surround your `show` method with a `begin / rescue` block. In the rescue block: rescue Exception => exc logger.error "exception: #{exc.message}" logger.error exc.backtrace.join("\n") end ` and then re-post the log. There is seomthing strange going on: the app performs a `Blog.find`, then raises a 500 error, then looks the user up, I guess you already have a begin/rescue/ensure block... – Idavod May 21 '13 at 01:46
  • I didn't already have a begin/rescue block in my code already. I don't know why it was looking the User up, perhaps something related to Devise? At any rate, it doesn't look for the user in the new log output. – John May 21 '13 at 02:21
  • John, now you get a 200 OK, is the solution suggested by Doon in place? Can you post the source? It might give clues or suggest ideas. Thanks. – Idavod May 22 '13 at 14:40

1 Answers1

7

in your applicationController you can should be able to rescue from the missing template, and then re raise a 404 .

class ApplicationController > ActionController::Base
  rescue_from ActionView::MissingTemplate do |exception|
     raise ActionController::RoutingError.new('Not Found')
  end
end
Doon
  • 19,719
  • 3
  • 40
  • 44
  • Not the best solution. You might want to get/track such exceptions in a production env in case something goes wrong. It would be better if we could send 404s only on mime types that you don't want to answer back. (a 406 is more 'correct' in terms of definitions but you probably want to hide your implementation details). Nevertheless your answer is a quick solution to solve the issue. – vasilakisfil Sep 02 '14 at 09:05
  • Well technically you could add the conditionals in the handler and do the tracking here as well. This is what OP wanted. (I've never had a need for something like this, and am not sure what I would in a production app here. – Doon Sep 02 '14 at 11:58