Information Technology Dark Side

Struggles of a Self-Taught Coder

Information Technology Dark Side header image 2

This guy hated the crazy view logic all over his rails app. You won’t believe the simple trick he used to fix it!

August 22nd, 2014 · 1 Comment

Sorry, I couldn’t help it. This style of headline is all over the place. It’s tacky, so this is me mocking it a little bit.

Yesterday I blogged about a distinction regarding DRY and posited an example of view code that is better with repetitive code than DRY code. I won’t rehash that, so here’s a link.

In the end of the post I mention that I want to be able to create views that are named like this:
– menu.html.haml (default)
– menu.bsa_troop.html.haml (alternate view for Boy Scout of America Troops)
– menu.sa_group.html.haml (alternate view for Scouts Australia Groups)

Yesterday I converted a few really ugly views to use this approach, just to test out the idea that the view code would be easier to read and work on. I was really satisfied with how it turned out, but I still had to do add some logic to render the right view based on the troop type.

In this post I’m going to show you how I created a file system resolver to get rid of any sort of if logic like this:

if @troop.is_bsa_troop?
  render 'menu.bsa_troop'
elsif @troop.is_au_group?
  render 'menu.sa_group'
else
  render 'menu'
end

There are two things I needed to do to make this work:
1) Create a special resolver to find the views based on the troop type
2) Tell the resolver what troop type we are using

The code isn’t fancy or hard to understand, so I’m just going to show it to you.

class ApplicationController < ActionController::Base
  include ApplicationHelper

  prepend_view_path UnitTypeResolver.new
  ... 
  around_filter :set_unit_type
  ...
  
  def set_unit_type
    Thread.current[:template_type] = @troop.try(:template_type)
    yield
  ensure
    Thread.current[:template_type] = nil
  end
  ...
end
class UnitTypeResolver < ActionView::FileSystemResolver
  def initialize
    super("app/views")
  end

  def find_all(name, prefix=nil, partial=false, details={}, key=nil, locals=[])
    unit_type = Thread.current[:template_type]
    if unit_type
      key = key.to_s + unit_type
      name = "#{name}.#{unit_type}"
    end
    super(name, prefix, partial, details, key, locals)
  end
end

Bam. menu.bsa_troop.html.haml gets rendered automatically if it exists and the troop is a Boy Scouts of America troop. If it doesn’t exist, it just renders menu.html.haml. This makes it super easy to create a totally different view of a feature for a specific type of troop, which makes my view code a lot easier to read and work on.

Thanks, @kofno, for helping me figure this out.

If you enjoyed this post, make sure you subscribe to my RSS feed!
Stumble it!

Tags: Uncategorized

1 response so far ↓

  • 1 Jacob "BoomShadow" Tirey // Sep 19, 2015 at 6:05 pm

    Your MOM likes to create special resolvers to display views. Heh heh. Couldn’t help myself. :) Actually, this was really helpful. Thanks for the sharing this. It’s simple yet effective.

Leave a Comment