Skip to content

Instantly share code, notes, and snippets.

@dwayne
Last active December 24, 2015 20:49
Show Gist options
  • Save dwayne/6860211 to your computer and use it in GitHub Desktop.
Save dwayne/6860211 to your computer and use it in GitHub Desktop.
My notes for some of the videos from RailsConf 2013

by Brendan Loudermilk

Unmaintainable templates result from the following:

  1. Markup repetition
  2. Logic in templates

Markup Repetition

Good designers repeat themselves (needed for a consistent design, good UX, etc), however good programmers don't.

To avoid markup repetition you should:

  • Abstract interface components
    • Figure out what is reused. Things like headers, footers, sidebars, navigation, breadcrumbs, ...
  • Use partials

That's it!

Logic In Templates

Some problems with putting logic in your templates include:

  • The markup can become highly repetitive
  • Painful to test

Possible solutions

Helpers

View helpers live in app/helpers and provide small snippets of reusable code for views.

Helpers are not the end all, be all for logic in your views. Problems with helpers include:

  • Big projects end up with tons
  • Difficult to organize
  • Complex logic isn't well suited for them
  • Doesn't feel right

Decorator Pattern

How can I take my models and add behavior to them specific for the views? Enter the decorator pattern.

Decorators attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality. ~ Design Patterns:Elements of Reusable Object-Oriented Software

Traits of a decorator:

  • Wraps a single object
  • Transparent interface
  • Forwards methods to original object

In our use case, it adds presentational logic to models without affecting the model itself.

# Implementing a Decorator in Ruby

class Decorator

  def initialize(component)
    @component = component
  end

  def method_missing(method, *args, &block)
    if @component.respond_to?(method)
      @component.send(method, *args, &block)
    else
      super
    end
  end

  # Recommended for proper etiquette
  def respond_to_missing?(method, *)
    @component.respond_to?(method) || super
  end
end

# Usage

class UserDecorator < Decorator
  
  def full_name
    "#{@component.first_name} #{@component.last_name}"
  end

  # ... more presentational methods
end

When to decorate?

Think about if what you are doing relates directly to a single instance of a model. If it does, then you should go with decorators.

There's a gem for that. Draper.

Implementing basic decorators is easy, but Draper adds a few helpful features:

  • Access to the view context
  • Easily decorate collections
  • Pretends to be the decorated object (helpful for form_for and such)
  • Easily decorate associations

That's not the end though. Having unique and/or complex UI behavior will quickly outgrow helpers and decorators.

Presenters

Sometimes what you want is an object that can represent the unique UI element and not the record it's displaying. Enter the presentation model.

The essence of a Presentation Model is of a fully self-contained class that represents all the data and behavior of the UI window, but without any of the controls used to render that UI on the screen. A view then simply projects the state of the presentation model onto the glass. ~ Martin Fowler

That is, dumb views.

TODO: Come up with an example of my own.

Other Tips

Resources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment