module ActionView::Helpers::AtomFeedHelper

Public Instance Methods

atom_feed(options = {}) { |atom_feed_builder| ... } Show source
# File actionview/lib/action_view/helpers/atom_feed_helper.rb, line 98
def atom_feed(options = {}, &block)
  if options[:schema_date]
    options[:schema_date] = options[:schema_date].strftime("%Y-%m-%d") if options[:schema_date].respond_to?(:strftime)
  else
    options[:schema_date] = "2005" # The Atom spec copyright date
  end

  xml = options.delete(:xml) || eval("xml", block.binding)
  xml.instruct!
  if options[:instruct]
    options[:instruct].each do |target, attrs|
      if attrs.respond_to?(:keys)
        xml.instruct!(target, attrs)
      elsif attrs.respond_to?(:each)
        attrs.each { |attr_group| xml.instruct!(target, attr_group) }
      end
    end
  end

  feed_opts = { "xml:lang" => options[:language] || "en-US", "xmlns" => "http://www.w3.org/2005/Atom" }
  feed_opts.merge!(options).reject! { |k, v| !k.to_s.match(/^xml/) }

  xml.feed(feed_opts) do
    xml.id(options[:id] || "tag:#{request.host},#{options[:schema_date]}:#{request.fullpath.split(".")[0]}")
    xml.link(rel: "alternate", type: "text/html", href: options[:root_url] || (request.protocol + request.host_with_port))
    xml.link(rel: "self", type: "application/atom+xml", href: options[:url] || request.url)

    yield AtomFeedBuilder.new(xml, self, options)
  end
end

Adds easy defaults to writing Atom feeds with the Builder template engine (this does not work on ERB or any other template languages).

Full usage example:

config/routes.rb:
  Rails.application.routes.draw do
    resources :posts
    root to: "posts#index"
  end

app/controllers/posts_controller.rb:
  class PostsController < ApplicationController
    # GET /posts.html
    # GET /posts.atom
    def index
      @posts = Post.all

      respond_to do |format|
        format.html
        format.atom
      end
    end
  end

app/views/posts/index.atom.builder:
  atom_feed do |feed|
    feed.title("My great blog!")
    feed.updated(@posts[0].created_at) if @posts.length > 0

    @posts.each do |post|
      feed.entry(post) do |entry|
        entry.title(post.title)
        entry.content(post.body, type: 'html')

        entry.author do |author|
          author.name("DHH")
        end
      end
    end
  end

The options for #atom_feed are:

  • :language: Defaults to “en-US”.

  • :root_url: The HTML alternative that this feed is doubling for. Defaults to / on the current host.

  • :url: The URL for this feed. Defaults to the current URL.

  • :id: The id for this feed. Defaults to “tag:localhost,2005:/posts”, in this case.

  • :schema_date: The date at which the tag scheme for the feed was first used. A good default is the year you created the feed. See feedvalidator.org/docs/error/InvalidTAG.html for more information. If not specified, 2005 is used (as an “I don't care” value).

  • :instruct: Hash of XML processing instructions in the form {target => {attribute => value, }} or {target => [{attribute => value, }, ]}

Other namespaces can be added to the root element:

app/views/posts/index.atom.builder:
  atom_feed({'xmlns:app' => 'http://www.w3.org/2007/app',
      'xmlns:openSearch' => 'http://a9.com/-/spec/opensearch/1.1/'}) do |feed|
    feed.title("My great blog!")
    feed.updated((@posts.first.created_at))
    feed.tag!('openSearch:totalResults', 10)

    @posts.each do |post|
      feed.entry(post) do |entry|
        entry.title(post.title)
        entry.content(post.body, type: 'html')
        entry.tag!('app:edited', Time.now)

        entry.author do |author|
          author.name("DHH")
        end
      end
    end
  end

The Atom spec defines five elements (content rights title subtitle summary) which may directly contain xhtml content if type: 'xhtml' is specified as an attribute. If so, this helper will take care of the enclosing div and xhtml namespace declaration. Example usage:

entry.summary type: 'xhtml' do |xhtml|
  xhtml.p pluralize(order.line_items.count, "line item")
  xhtml.p "Shipped to #{order.address}"
  xhtml.p "Paid by #{order.pay_type}"
end

atom_feed yields an AtomFeedBuilder instance. Nested elements yield an AtomBuilder instance.

© 2004–2019 David Heinemeier Hansson
Licensed under the MIT License.