bjork24
bjork24

Reputation: 3183

Rendering safe html in Rails 3

I have a database filled with old blog posts that I'm trying to migrate over to Rails. The body field consists of posts that look have a format similar to this:

Paragraph text paragraph text paragraph text and even more paragraph text. Paragraph text paragraph text paragraph text and even more paragraph text. Paragraph text paragraph text paragraph text and even more paragraph text. Paragraph text paragraph text paragraph text and even more paragraph text.

<iframe src="http://www.youtube.com?v=XXXXXXXX" width="400" height="250"></iframe>

Paragraph text paragraph text paragraph text and even more paragraph text. Paragraph text paragraph text paragraph text and even more paragraph text. Paragraph text paragraph text paragraph text and even more paragraph text. Paragraph text paragraph text paragraph text and even more paragraph text.

<ul>
<li>List item</li>
<li>List item</li>
<li>List item</li>
<li>List item</li>
</ul>

Paragraph text paragraph text paragraph text and even more paragraph text. Paragraph text paragraph text paragraph text and even more paragraph text. Paragraph text paragraph text paragraph text and even more paragraph text. Paragraph text paragraph text paragraph text and even more paragraph text.

So what I'm trying to do is wrap the paragraph text in <p>, but leave the other html elements alone. Here's what I've tried:

simple_format(@post.body) = this puts <p> around everything, but also pollutes my unordered lists with breaks between each list item. Also, the iframe embed won't show up.

raw(@post.body) or @post.body.html_safe = The iframe embed and unordered lists show up great, but everything is running together since there's no substitution for new lines.

simple_format(@post.body, {}, {:sanitize => false}) = Cool. Now I can see all the html tags! Doesn't work at all

@post.body.gsub(/\r\n?/,"<br/>").html_safe = Same problem as with simple_format... I'm getting line breaks in my html block element tags.

Any suggestions on how to accomplish this?

Upvotes: 1

Views: 4820

Answers (3)

big-circle
big-circle

Reputation: 547

I think sanitize maybe what you want

%= sanitize @article.body %>


def sanitize(html, options = {})
  self.class.white_list_sanitizer.sanitize(html, options).try(:html_safe)
end

Upvotes: 1

Kelvin
Kelvin

Reputation: 20857

I think your question has less to do with rails than trying to fix broken html. In any case, your example suggests that the text that should be wrapped in <p> tags are the lines that don't already start with a tag. Only you know if this rule applies to the other posts.

Try this. It also accounts for leading whitespace.

raw( @post.body.gsub(/^\s*[^<].*/, '<p>\&</p>') )

If the above is too fragile, I suggest using Nokogiri. This takes each top-level contiguous block of text and wraps it in <p>:

doc = Nokogiri.XML("<body>\n" + @post.body + "\n</body>\n")
doc.root.children.each{|c| c.text? and c.replace("<p>#{c.to_s.strip}</p>") }
raw( doc.root.inner_html )

To insert <br>s at the linebreaks in the text blocks, you can replace c.to_s.strip above with c.to_s.strip.gsub(/\r?\n/, "<br/>\n").

I noticed your question had /\r\n?/. Are you ever expecting the old Mac OS carriage return (\r) by themselves? If you want to want to handle Windows or Unix you should use /\r?\n/.

Upvotes: 1

RyanWilcox
RyanWilcox

Reputation: 13974

I think you almost had it in your last example, but my guess is that you need to do the .html_safe earlier:

@post.body.html_safe.gsub(/\r\n?/,"<br/>") 

Upvotes: 2

Related Questions