Fork me on GitHub
Hoopla! - now with extra whiz-bang home

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](http://therealadam.com/archive/2008/06/05/oh-the-fail-ive-known/), 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
blog comments powered by Disqus