Autonomous Machine

Inheritable Page Attributes in Rails

On most webpages there are a number of what I call 'page attributes'. These are little bits of data that have to be set based on the context of the app: the page title, a body class, etc.

It's easy enough to just use content_for to handle this scenario:

# in a view template
content_for(:title, 'Epic Page Title')

# in the page layout
yield :title

But I've found I often want to define these things at a higher level, perhaps at the controller level, either using a class method or inside an action body like this:

class UnicornsController
  page_attr :body_class, 'unicorns'
  def party
    # such a special action deserves a special class
    page_attr :body_class, 'unicorn-party'
  end
end

Or even in a view:

<%- page_attr :body_class, 'out-of-control-unicorn-shindig' -%>

This is a contrived example, but the idea is page attributes are inherited the way one would expect (controller class -> controller action -> template), while potentially being overridden at the lower levels. Here's the code:

# in app/controllers/application_controller.rb
include PageAttributes

# in config/initilizers/requires.rb
require 'page_attributes'

# in lib/page_attributes.rb
module PageAttributes
  def self.included(base)
    base.helper_method :page_attr
    base.class_attribute :page_attributes
    base.page_attributes = {}
    base.class_eval do
      def self.page_attr(key, value)
        self.page_attributes[key] = value
      end
    end
  end

  protected

  def page_attr(key, value=nil)
    @page_attributes ||= {}
    if value.nil?
      @page_attributes[key] || self.class.page_attributes[key]
    else
      @page_attributes[key] = value
    end
  end
end