I’ve got a couple Rails controllers that just serve static content like graphics and script assets. In production the content is all cached so it bypasses the controller but when I’m running locally I’ve got pages and pages of garbage filling up my development log.
The first attempt at silencing the whining controllers used an around_filter that looked something like this:
class GraphicsController < ApplicationController
around_filter :no_logging
protected
def no_logging
logger.silence { yield }
end
end
which is great, compact, easy to encapsulate, etc. But it doesn’t work. Debugging told me I needed to use a different logger object and put this code in a different place. I share this next piece of code not out of pride but as an example that I, like Adam Keys, am a student of the art of abysmal failure. Here’s my original implementation:
# in ./lib/exempt_controllers_from_logging_entirely.rb
module ExemptControllersFromLoggingEntirely
@@controllers_to_exclude = %w(graphics styles scripts)
def self.included(base)
base.class_eval do
def process_with_no_logging(request, *args)
if @@controllers_to_exclude.any? {|controller| request.parameters[:controller] == controller }
logger.silence { process_without_no_logging(request, *args) }
else
process_without_no_logging(request, *args)
end
end
alias_method_chain :process, :no_logging
end
end
end
ActionController::Base.send :include, ExemptControllersFromLoggingEntirely
Yay! It’s HUGE! And it uses all the unnecessary complexities of alias_method_chain and self.included and, oh joy, the controllers that use it are specified RIGHT IN THE CODE.
Sadly, this code worked fine. Ruby lacks an ugly-code warning system that tells me when I’m writing something unwieldly.
Here’s the refactored version:
# in ./lib/exempted_from_logging.rb
module ExemptedFromLogging
def process(request, *args)
logger.silence { super }
end
end
## Usage:
## class GraphicsController < ApplicationController
## include ExemptedFromLogging
## end
Yeah.
Lesson?
* If you’re just overwriting a single method like this put it in a module that calls super * If you’re bypassing a method entirely then you can think about aliasing or overwriting the original * Avoid using self.included and self.inherited unless you’ve got something complex to do like adding both instance and class methods to an object * Remember to revisit your old code * Blog your failures for fun and profit humility
-
Ted said:
you might wanna consider triggering that wrapper based on environment, or an environmental flag - it might be an expensive operation in a production environment. complete speculation, but something to consider.
blog comments powered by DisqusRelated Posts
Jack Danger Canty
Ruby and Javascript developer @ Cloops Local Coupons
jackcanty.com
github.com/JackDanger
twitter.com/jackdanger
flickr.com/photos/jackdanger