新コンテンツを知らせよう - RSSの追加

2018-02-25



このブログはRailsを使ってフルスクラッチで作られているワケだが、残念な事にRSSフィードの出力をまだ実装していない。しかしRSSフィードを出力すれば定期的にこのブログを見てくれる人も増えるだろうし、諸々のサービスへ連携するのも可能になる。だから今日作るよ。

おそらくRSSフィードを作成するgem、という文言でググるとHit数が少なく選択肢がないように思えるかもしれない。だが実際にはRSSパーサーgemのほとんどはRSSフィードの出力も出来る。当然と言えば当然である。

今回はgemではなく単にxmlとしてBuilder::XmlMarkupで書く。理由はRSS部分がviewとして分離できて気持ちいいから。

1 MVCの実装
2 ルーティングの追加

これだけ。難しいことは特にない。

基本方針

実装をどこから始めてもいいが、まず先に基本方針を決める必要がある。つまりRssを独立したリソースとして扱うか、あるいはRSSに記述するコンテンツであるEntryリソースのViewの一種として扱うかだ。今回は前者で行こう。コンテンツがEntry以外にも作られるかもしれないし、URLとオブジェクトが一致している方が直感だ。ただし実装すべき部分が増える。

VCの実装

特に難しいところはない。FeedControllerとViewを作る。ModelやServiceまで作る必要は無いので今回はこれだけ。

Controller

class FeedController < ApplicationController
  def show
    @entries = Entry.where("created_at < ?", 3.hour.ago).order(created_at: :desc).limit(20)
#   respond_to(&:rss) ワンラインの誘惑に負けてはいけない、可読性を大事に 
    respond_to do |format|
      format.rss
    end
  end
end

ところで、たまに○○Controllerを必ず複数系で、かつトップページ相当のメソッドをindexで作る人もいるが自分は今回のFeedのようにユニークで集合体にはならないリソースに関するコントローラーは単数系で書くしindexも使わずshowアクションで書く。
(HomesControllerのindex? HomeリソースがDBに存在してその一覧を出すのか?

やることは単純。フォーマットをrssに指定してviewへrss.builderのようにファイルを作る。最初に書いたがBuilder::XmlMarkupでやっていく、あまり聞かないかもしれないがbuilderはxml用のテンプレートエンジン。

Entryの検索条件に3時間前を指定しているが、これは単に自分が公開後に頻繁な書き直しを行う為の猶予時間なので気にしない。

View

#encoding: UTF-8
cache 'feed_cache_key', expires_in: 1.day do
  xml.instruct! :xml, version: '1.0'
  xml.rss('version' => '2.0', 'xmlns:dc' => 'http://purl.org/dc/elements/1.1/') do
    xml.channel do
      xml.title Settings.title
      xml.description Settings.description
      xml.link Settings.home_url
      xml.language 'ja-ja'
      xml.ttl '1440'
      @entries.each do |entry|
        xml.item do
          xml.title entry.title
          xml.description do
            xml.cdata! truncate(strip_tags(markdown(entry.body)), omission: '...', length: 500)
          end
          xml.pubDate entry.created_at.rfc822
          xml.guid entry.full_uri
          xml.link entry.full_uri
        end
      end
    end
  end
end

注意として、RSSでは日時をRFC822準拠にしなければならないので.rfc822メソッドで変換しておく。

あと、このレンダリングは少し重い。20件のレコードを取って来てMarkdownで記述された記事の本文をHTMLにレンダリングしなければならない。Disk I/OとしてもCPU的にもメモリ的にも割と食う。流石にここはキャッシュしておこう。場合によっては頻繁に呼び出される部分なので一応ね。本来なら全部の記事をMarkdownからHTMLに変換した状態でDBに置いておくほうが高速だがまだやっていない。コンテンツが少なくてアクセス数が低い状態では優先度が無限に低い。

ルーティングの追加

新規のurlを追加してなければならないのでconfig/routing.rbあたりに記述を追加しよう。

get '/feed', to: 'feed#show', format: 'rss'

特に難しいところはなし。注記としてはformat: 'rss'をつけないとrails4からUnknown Format Errorを起こすようになったので指定が必要。

HTMLにRSSの存在を記述する

さて、このフィードのリンクをページ内に貼っておくだけでもいいのだが、HTMLのHEAD内にRSSが存在していることを明示的に記述することも出来る。

<link rel="alternate" type="application/rss+xml" title="RSS" href="/rss.xml" />

こうして明示的に記述することでブラウザの拡張機能でアクセス時に自動でRSSの存在を検出したり、何かしらのボットがRSSを見つけやすくなる。

参考リンク

https://easyramble.com/rails-builder-rss-feed.html
https://qiita.com/klriutsa/items/6662ef75e804c4323228


 このエントリーをはてなブックマークに追加


<< さぁ、高速化だ!