Search code examples
htmlruby-on-railsatom-feed

Rails atom_feed: How to add HTML tags like <h1> to the feed content?


I want to structure the content of my Atom feed using headings:

atom_feed do |feed|
  feed.title "#{Page.model_name.human(count: :other)} - #{t('app.name')}"
  feed.updated(@pages[0].created_at) if @pages.length > 0

  @pages.each do |page|
    feed.entry(page) do |entry|
      entry.title(page.title)
      entry.content(type: 'html') do |html|
        html.h1 t('.position_in_hierarchy')
        html.p page.ancestors.reverse.map(&:title).join ': '

        html.h1 Page.human_attribute_name :lead
        html.div markdown page.lead

        html.h1 Page.human_attribute_name :content
        html.div markdown page.content
      end
    end
  end
end

For each of my pages, this results in the following generated XML:

<entry>
  <id>tag:localhost,2005:PageDecorator/1</id>
  <published>2017-02-24T18:11:26+01:00</published>
  <updated>2017-04-05T09:58:42+02:00</updated>
  <link rel="alternate" type="text/html" href="http://localhost:3001/en/pages/1"/>
  <title>Preparation</title>
  <content type="html">
    <h1>Position in page hierarchy</h1>
    <p>Preparation</p>
    <h1>Lead</h1>
    <div>&lt;p&gt;This the lead.&lt;/p&gt;</div>
    <h1>Content</h1>
    <div>&lt;p&gt;This is some content!&lt;/p&gt;
&lt;h2 id="with-a-heading"&gt;With a heading&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://www.example.com"&gt;And a link!&lt;/a&gt;&lt;/p&gt;</div>
    <h1>Notice about Atom feed</h1>
    <p>Your feed reader has downloaded version 14 of the current page, which was current at April 05, 2017 09:58. Meanwhile there could be an updated version of the page available online. Visit the original page to see the most current version!</p>
  </content>
</entry>

As you can see, the html.h1 calls are rendered as plain <h1>. But interestingly, my feed reader Vienna doesn't display them! More interestingly, the content of html.div, which is markdown rendered by my custom markdown method, is html escaped... and this stuff is rendered by Vienna!

screenshot

The markdown method itself escapes HTML:

def markdown(string)
  PandocRuby.convert(string, to: :html).html_safe
end

So I'm pretty unsure now what to do to make my other HTML markup work in Vienna, too.


Solution

  • As Kris pointed out in his comment, the content needs to be escaped: https://validator.w3.org/feed/docs/atom.html#text

    The easiest thing to do this is just rendering a partial like this:

    entry.content(render(page), type: 'html')
    

    This will render _page.atom.slim (or .erb or whatever) and automatically escape the HTML.