Como adicionar suporte a feeds

Imaginei que adicionar suporte a feeds em uma aplicação Rails fosse complicado. Mas uma vez “tomei na cabeça” vendo que o Rails realmente é produtivo de se trabalhar :)

1. Método de consulta que retorna todos os posts. Para criar uma URL de feed para o seu blog, antes de tudo você precisa criar um método que faça uma query que liste todos os posts do blog. Seguindo a filosofia “fat model / skinny controller” este método deve ficar dentro do próprio model “Post”. Vamos criar um método chamado “all_posts”.


# app/models/post.rb
class Post < ActiveRecord::Base
  has_many :comments

  def self.all_posts
    find(:all, :order => "created_at DESC")
  end
end

2. Criando uma action para feeds. Agora vamos adicionar uma action chamada “feed” dentro do controller “posts’. Repare que aqui já estamos usando o método “all_posts” criado no passo anterior.


# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def feed
    @posts = Post.all_posts

    respond_to do |format|
      format.atom
    end
  end
end

3. Adicionando uma rota. Do jeito que está, não existe como acessar a URL http//www.myblog.com.br/feed, porque ainda não temos uma rota para esta URL. Precisamos adicionar esta rota no arquivo config/routes.rb. Note a última linha do arquivo.


# config/routes.rb
  map.root :controller => 'posts'
  map.resources :posts, :has_many => :comments
  map.resources :sessions
  map.feed 'feed', :controller => 'posts', :action => 'feed'

4. Adicionando um template para o feed.. Ok, agora o Rails já sabe que existe uma URL /feed em nosso blog. Mas ele não sabe o que renderizar ali, na action “feed”. Ele só sabe que possui um objeto @posts disponível. Vamos dizer ao Rails como ele deve formatar esse retorno. O exemplo abaixo foi retirado da própria documentação do Rails, do Helper AtomFeedHelper.


# app/views/posts/feed.atom.builder
atom_feed(:language => "pt-BR") do |feed|
  feed.title(h "My blog")
  feed.updated((@posts.first.created_at))

  for post in @posts
    feed.entry(post) do |entry|
      entry.title(post.title)
      entry.content(post.body, :type => 'html')

      entry.author do |author|
        author.name(h "João da Esquina")
      end
    end
  end
end

Você pode testar essa URL em seu browser. Mas provavelmente é melhor testar com o comando curl e ver o resultado completo:


curl --get http://www.myblog.com.br/feed

5. Feed no <HEAD> do site. Pronto, já temos um feed funcionando. Agora precisamos colocar isto em nosso HTML, para dizer ao mundo que nosso blog já tem suporte a feeds :) A melhor forma é usar o helper auto_discovery_link_tag do Rails:


# app/views/layouts/application.html.erb
<head>
  <%= auto_discovery_link_tag(:atom, :controller => 'posts', :action => 'feed') %>
</head>

Agora nosso blog informa aos leitores de feeds, que nossa URL oficial é o /feed que criamos até agora. Mas se você como eu, prefere usar o FeedBurner para isso, ao invés disso faça assim:


# app/views/layouts/application.html.erb
<head>
 <%= auto_discovery_link_tag(:atom, 'http://feeds.feedburner.com/LevyOnRails', :title => "My blog's feed") %>
</head>

Ok. Agora se você informar a url de seu blog, por exemplo, http://www.myblog.com.br/ (sem o /feed) no Google Reader ou outro leitor de feeds experto, ele vai usar o feed do FeedBurner, no meu caso a URL http://feeds.feedburner.com/LevyOnRails. Perfeito!

Mas e se alguém usar a url http://www.myblog.com.br/feed, desconsiderando o que está na tag auto_discovery_link_tag acima? Para isso precisamos adicionar um redirect para o feed.

6. Redirect para o feed. Vamos criar um redirect, de forma que somente o FeedBurner consiga ler a nossa URL /feed. O restante do mundo será redirecionada para a URL do http://feeds.feedburner.com/LevyOnRails. Qual a vantagem disso? Você não terá metade de seus leitores usando o FeedBurner e outra metade usando o feed direto de teu site. Assim você consegue medir 100% a leitura/visitação de seu feed, usando as facilidades disponíveis no site do FeedBurner. Vamos precisar alterar o nosso controller:


# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def feed
    redirect_to 'http://feeds.feedburner.com/LevyOnRails', :status=>307 and return unless request.env['HTTP_USER_AGENT'].match(/feedburner|feedvalidator/i)

    @posts = Post.all_posts

    respond_to do |format|
      format.atom
    end
  end
end

Com isso verificamos a variável do servidor HTTP_USER_AGENT, se esta contém a string “feedburner” ou “feedvalidator”. Se tiver, nós acreditamos que trata-se do FeedBurner, e somente este agent pode acessar nossa URL feed real.

E isso é tudo. Simples, não? :)

Share and Enjoy:
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google

Tags: , , , ,

Leave a Reply