views:

33

answers:

2

My Song model has a lyrics text attribute. Since new lines are \n-separated in my lyrics, I often find myself doing this in my views to make the lyrics HTML-friendly:

@song.lyrics.strip.gsub(/\n/, "\n<br />")

I'm repeating the gsub logic all over my application, and, worse still, I can't change the format in which I store my lyrics without touching everywhere I tried printing them as HTML.

I'd like to abstract this so that I can write this in my views:

@song.lyrics.to_html

So that the strip.gsub(/\n/, "\n<br />") logic is present in only one place in my application (in the to_html method).

What's the best way to do this?

+1  A: 

If you need to use the exact @song.lyrics.to_html syntax and you don't want to create a Lyrics model, you can add a singleton method to the string returned by the lyrics method:

class Song
  def lyrics
    str = read_attribute(:lyrics)
    def str.to_html
      strip.gsub(/\n/, "\n<br />")
    end
    str
  end
end

However, this is not really a great design. For something more re-usable you might want to write a module with a to_html method like this:

module HtmlFormatter
  def to_html(attribute)
    send(attribute).strip.gsub(/\n/, "\n<br />")
  end
end

If you include HtmlFormatter in your Song model you can call the method like this:

@song.to_html(:lyrics)

So it doesn't follow your desired syntax exactly, but I think it's a better design.

You might also want to consider a separate Lyrics model which could have all kinds of features, but this might be too heavy for your application.

Alex Reisner
Definitely don't want a lyrics model. The `HtmlFormatter` module sounds good, but it conflicts with acts_as_markdown (which mixes in a separate `to_html` method for markdown attributes)
Horace Loeb
Why not just use markdown? It will give you the line breaks you want, right? If you don't want to use it, you'll obviously have to rename the method...
Alex Reisner
Also, won't your lyrics method return `nil` as written? (Needs to return `str` after the method definition)
Horace Loeb
"It will give you the line breaks you want, right?" -- no; markdown (somewhat confusingly) ignores single newlines
Horace Loeb
Didn't know that--I've always worked with Textile (RedCloth gem). And yes, you're right that my method needs to return `str`--I just fixed it.
Alex Reisner
A: 

Since is a view-related issue, you can place your to_html method on the ApplicationHelper module

module ApplicationHelper

  def to_html(str)
    str.strip.gsub(/\n/, "\n<br />")
  end

end

so, on your views :

<% = to_html(@song.lyrics) %>
Lucas