【Ruby on Rails】Atomフィードの実装

■まずXMLファイルを生成する方法として、大きく分けて2つの方法がある。

  1. 動的に生成する。(.rxmlファイルを使う)
  2. 静的に生成する。(cronなどを使って、メソッドが実行されたと時にファイルを生成する)

今回はそれぞれについて、まとめていく。

■動的に生成する。

1. まず以下のサンプルを参考に、rxmlファイルを作る。
●sample_feed.rxml

xml.instruct! :xml, :version => "1.0", :encoding => "UTF-8"
xml.feed('xmlns' => 'http://www.w3.org/2005/Atom') do
  xml.title @feed_title
  xml.subtitle @feed_subtitle
  xml.link "href" => (request.protocol + request.host_with_port + url_for(:rss => nil)),
      "rel" => "self","type" => "application/atom+xml"
  xml.author @feed_author
  xml.id @feed_id
  xml.updated Time.now
    @events.each do |ev|
      xml.entry do
        xml.title ev.title
        xml.link "href" => (request.protocol + request.host_with_port +
                 url_for(:controller => 'hoge', :action =>'foge'))
        xml.id ev.id
        xml.updated ev.update
        xml.summary ({:type => "text/html", :mode => "escaped"}, ev.summary)
      end
    end
end

2. 次にcontrollerでインスタンス変数とheaders["Content-Type"]を渡します。

※ここでheaders["Content-Type"]を指定することで生成するviewのフォーマットを指定出来ます。デフォルトは"text/html"。

●sample.rb

def sample_feed
  @feed_title = "sample"
  @feed_subtitle = "sub"
  @feed_author = "sample"
  @feed_id = "sample_id"
  @events = 動的に生成
  headers["Content-Type"] = "text/xml; charset=UTF-8"
  render :layout => false
end

3. これで、@eventsが生成される度にxmlファイルが生成される!簡単ですね〜Railsさん、さすがです★

■静的に生成する。-cronの利用
  • 今回作る機能では、動的に実装してしまうと一定期間データがなくて不具合が起きてしまうため、静的に実装し直すことにした。
    • Modelに機能を実装して、Cronを利用することで毎日一定時間にそのメソッドを実行する。
  • Modelでは機能毎に細かく4つのメソッドに分けた。
    1. headerを生成するメソッド
    2. entriesを生成するメソッド
    3. xml(atom)ファイルを生成するメソッド
    4. xml(atom)ファイルを書き出すメソッド

以下にサンプルを記述します。

●sample_rss.rb

def self.header                  
  {:title => XML_TITLE,
   :subtitle => XML_SUBTITLE,
   :author => XML_AUTHOR,
   :id => XML_ID,
   :updated => Time.now.strftime("%Y-%m-%d %H:%M"),
   :link => XML_LINK
  }
end

def self.entries                  
  events = Event.find(:all, conditions =>["条件"])
  entries = []
  events.each do |event|
    entries << {:title =>     "#{event.title}",
                :link =>      "#{event.link},
                :published => "#{event.published}",
                :updated =>   "#{event.updated_at}",
                :id =>        "#{event.id}",
                :summary =>   "#{event.summary}"
               }
    end
  entries
end

def self.create_atom(header ={}, entries = [])   
  xml = Builder::XmlMarkup.new
  xmlobj = xml.feed("version" => "1.0", "xmlns" => "http://www.w3.org/2005/Atom",
           "encoding" => "UTF-8") do
   
    xml.title header.values_at(:title)
    xml.link({:type => "application/atom+xml", :href => header.values_at(:link)})
    xml.subtitle header.values_at(:subtitle)
    xml.author header.values_at(:author)
    xml.id header.values_at(:id)
    xml.updated header.values_at(:updated)
      
    entries.each do |en|
      xml.entry do
        xml.title en.values_at(:title)
        xml.link({:href => en.values_at(:link)})
        xml.published en.values_at(:published)
        xml.updated en.values_at(:updated)
        xml.id en.values_at(:id)
        xml.summary({:type => "text/html", :mode => "escaped"}, en.values_at(:summary))
# {:type => "text/html", :mode => "escaped"}これの指定で、summary要素の中で、
# HTMLタグが利用できるようになる。
      end
    end
  end
  xml
end

def create_atom_file                 
  out_file_name = "#{RAILS_ROOT}/public/xml/#{XML_FILE_NAME}" 
 #保存するXMLファイルの場所を指定
  xml = self.create_atom(self.header, self.entries)
  file = File.open(out_file_name, 'w') 
    file.puts xml.to_s.sub!(/<to_s\/>/, "")   
 #to_sで配列を文字列に変換 & sub!(/<to_s\/>/, "")で"to_s"を空白に置換。
  file.close

  #send_ping ←ping送信についてはまた後日まとめます。
  self.send_ping_for_date
end
  • あとはcronを回して一定時間で"SampleRss.create_atom_file"を実行すればOK!!
■Cronの設定-今回はscript/runnerを利用した。
ruby script/runner "SampleRss.create_atom_file"
  • cronで定期起動する。
0 0 * * *   ruby /home/napzak/foo/script/runner "SampleRss.create_atom_file"

※cronの時間設定については以下を参照。

http://d.hatena.ne.jp/satake7/20080615/p1

  • ちなみに引数を渡すことも出来ちゃう。
ruby script/runner "SampleRss.create_atom_file(123)"
ruby script/runner "SampleRss.create_atom_file 123"
★結論

実装にはかなり時間がかかりましたが、まとめてみると案外シンプルなものでした。。

やはり実装に取り掛かる前に徹底的な情報収集をする必要がありますね!


最後までお読み頂き、ありがとうございました。