Manage your markup with has_markup

I recently decided to extract some plugins, in an effort to clean up the codebase for my blog.

The first thing I tackled was generation of HTML from my Post model.

In the beginning…

Here’s the starting point for my model:

class Post < ActiveRecord :: Base # --- SNIP --- # TODO move into own file... and plugin? def self . validates_markdown ( * attrs ) validates_each ( * attrs ) do | record , attr , value | begin BlueCloth . new ( value ). to_html unless value . nil? rescue BlueCloth :: FormatError => e errors . add attr , "has #{ e } " end end end validates_presence_of :content validates_markdown :content before_save :cache_content # Use BlueCloth to generate HTML ahead of time. def cache_content html = BlueCloth . new ( self . content ). to_html self . cached_content = html end # --- SNIP --- end

validates_markdown really doesn’t belong here, and nothing interesting is happening, but the lines of code start to add up.

Let’s look at the partial for Post .

%div { :id => dom_id ( post ), :class => dom_class ( post ) } %h2 .title = link_to ( post . title , post ) .content ~ post.cached_content

Eh, nothing particuarly interesting.

Goals

One-liner for specifying markup, similar to has_many or acts_as_taggable

or Optionally require the markup

Optionally cache the markup

Allow for different syntaxes

A whole new look on things

I was able to extract the logic out of my model and hit all of these goals.

The refactored model:

class Post < ActiveRecord :: Base # --- SNIP --- has_markup :content , :required => true , :cache_html => true # --- SNIP --- end

And the view is more or less the same:

%div { :id => dom_id ( post ), :class => dom_class ( post ) } %h2 .title = link_to ( post . title , post ) .content ~ post.cached_content_html

Thoughts

Plugins are really easy to make

Plugins can pull a good amount of code out of your model, which results in it being more readable

I think I finally understand the difference between include and extend

Get it

If you’re interested in trying this plugin, it is hosted on GitHub. You can install it by with: