ブログのサイドバー
ブログのサイドバーって、実装がめんどくさそうです。そこで、Rails流サイドバーの作り方。componentsとカウンタキャッシュが使えます。
ブログツールを作るときに、実装が一番めんどくさいのは、サイドバーです。このサイトでいえば、右側水色の「カテゴリ別」あたり。
サイドバーの情報は、ページを表示するたびに、データベースをベロりと走査して集計しなければなりません。しかも、本来の目的のactionとは分離したところに集計ロジックを組まなければならないので、悩みどころです。
Railsには、サイドバーを作るためのうまい方法が用意されてるので、紹介します。※コレを使っても、内部で大量のSQLが実行されることには変わりないので、ページキャッシュと合わせて利用してます。
railsapp/の下にある components/ってなんだべ?と思って調べてたら、CMSプラグインやポートレットのような、小さいモジュール単位で機能を組み込むしくみのようです。
components/の下に、小さなアプリケーション「sidebar」を作ってみます。
配置:
railsapp/components/sidebar/
components/sidebar/summary_controller.rb
components/sidebar/views/recent.rhtml
summary_controller.rb:
class Sidebar::SummaryController < ApplicationController
uses_component_template_root
#viewがcomponents/にある。という宣言。
def recent
@items = Item.find(:all,:order=>"created_at desc",:limit=>10)
render :template=>"sidebar/views/recent.rhtml"
end
end
そして、recent.rhtmlでは、@itemsの表示ロジックを書きます(省略)。
次に、作った「sidebar」をブログ本体に組み込みます。本体のviewに、次を追加します。通常は、views/layouts/template.rhtmlなどに書くと効率的。
<%= render_component \
:controller => "sidebar/summary", :action=>"recent" %>
あとは同じように、components/sidebar/の下にactionとviewを増やしていけば、出来上がりです。
カテゴリ毎の投稿件数や、記事毎のコメント数などの取得には、
SELECT COUNT(*)をたくさん実行しなければなりません。いちいちSQLを使ってカウントするのは気が引ける場合、カウンタキャッシュが使えます。
テーブル:
categories.items_count と items.category_id は、命名規約に合わせています。
CategoryとItemをhas_many,belongs_toの関係します。そうすると、Categoryに所属するItemの件数は、
<%= category.items.size %>
で取得できますが、この瞬間に内部で、
select count(*) from items where category_id=?
が走ってしまいます。これを防ぐには、モデルクラスにcounter_cacheの設定をします。
class Category < ActiveRecord::Base
has_many :items
end
class Item < ActiveRecord::Base
belongs_to :category, :counter_cache => true
end
これで、itemsの更新したときにcategories.items_countが自動的に更新されて、category.items.sizeの結果は、ココから取得するようになります。
考え方としてはよくある手法ですが、宣言イッパツで自動的にやってくれるのが、Railsらしくていいですね。
componentsを知る前は、before_filterで集計したり、viewに直接ロジックを書いたりして凌いでました。使えば使うほど、よくできてるフレームワークだと感じます。ちょっとscaffoldしたくらいでは、Railsの本当の良さはわからんですな。

