AtomPubな何かを作ってみよう その7 〜実装編 Part.06「各リソース間を接続しよう」〜

今回は各リソース間の接続性のお話です。

接続性は大事

RESTfulWebサービスにとって、接続性(Connectedness)は重要な要素の一つです。どのリソースとどのリソースが繋がっているのかが明示的に示されていないと、どこからも接続されていない孤立したリソースができてしまったりします。

…という事は重々承知していたものの、本シリーズのここまでの記事で作成したリソースは残念ながら全く接続されていません…。

このままではRESTfulWebサービスとしてはよろしくないので、それぞれのリソースを接続する事を考える事にしましょう。

リンクの設計を考える

まずは、どんなリンクが必要になるか考えてみましょう。

今のところ、名付けて.ね〜むの各リソースは次のようなリンクを持っています。

実線はlinkタグで既にリンク済みのもの、破線は前回、サービス文書によって関係性を紐付けたものです。

サービス文書による紐付けは、クライアントが必ずしも対応してくれるとは限らない為、多少弱い紐付けと言えるので、きちんとlinkタグでリンクするようにしましょう。

また、子リソースがどのリソースの子供なのか分かるように、子→親の関係もリンクするようにします。これで、次のようなリンクが作られる事になります。


コードとしてはViewにリンク要素を追加していく形になります。

例として、meaningsリソースから子リソースへのリンクの場合は次のように、"app/views/meanings/entry.rxml"に追加します。

  entry.link(:rel => 'related', :href => meaning_url(@meaning.name)+'/comments')
  entry.link(:rel => 'related', :href => meaning_url(@meaning.name)+'/namedwords')

逆に、namedwordsリソースからmeaningsリソースのような子リソースから親リソースへのリンクの場合は次のように、"app/views/namedwords/feed.rxml"に追加します。

  feed.link(:rel => 'related', :href => meaning_url(@meaning.name))

これを、図中の赤い線全てについて実施していけば、各リソース間が接続されたWebサービスになります。

ページングを実装する

更に、ついでなので各Feedのリソースにページングのリンクも入れるようにしましょう。

Railsのページングに関しては、以下の記事と、この記事からの一連の追記辺りを参考にさせて頂きました。
Ruby on Rails 2.0.1に対応 - idesaku blog

まずは、ページングのプラグインをインストール。

$ gem sources -a http://gems.github.com/
$ gem install mislav-will_paginate

あとは、environment.rbの末尾にrequireを追加すれば準備はオッケー。

require 'will_paginate'

続いて、Controllerでfindで記事の一覧を取得していたところを、paginateで取得するように変更します。

#@meanings = Meaning.find(:all, :conditions => condition, :order => 'updated desc', :limit => 20)
@meanings = Meaning.paginate(:conditions => condition, :order => 'updated desc', :page => params[:page], :per_page => 20)

最後に、Viewで最初・最後・前・次のリンクを出力するようにすれば完成です。

  feed.link(:rel => 'self', :href => meanings_url)
  feed.link(:rel => 'first', :href => meanings_url+'?page=1') if ( @meanings.size > 0 )
  feed.link(:rel => 'prev', :href => meanings_url+'?page='+@meanings.previous_page.to_s) if ( @meanings.previous_page )
  feed.link(:rel => 'next', :href => meanings_url+'?page='+@meanings.next_page.to_s) if ( @meanings.next_page )
  feed.link(:rel => 'last', :href => meanings_url+'?page='+@meanings.total_pages.to_s) if ( @meanings.size > 0 )

一応、それぞれ必要な時だけ出力するように、if文をくっつけています。非常にあっさり実装できて素晴らしいですね。

ちなみに、色々なサイトを見て調べながらやっていたんですが、will_paginateの実装がバージョンによって違うのか、各値の取得方法が何種類か見つかって、どれが正しいのか分からなくて困りました…。

総ページ数の取得が、サイトによって"total_page"だったり"page_count"だったり…。結局のところ、今回インストールしたwill_paginateは2.3.8で、このバージョンだと上記のように、"total_pages"で総ページ数が取得できました。*1

という訳で、今回は各リソース間の接続についてのお話でした。

次回は?

次回は、ユーザリソースを新たに追加して、認証・認可に関する辺りに入っていこうかと思います。

*1:何か、Railsってバージョンによる違いが多くて、今回みたいに色んなサイトを当たっても書いてある事が違う事が多い気がする…のは私の気のせいなんでしょう…という事にしておこう…。