読者です 読者をやめる 読者になる 読者になる

すがブロ

sugamasaoのhatenablogだよ

モデルにメソッドを持たせる

こんな感じの投稿システムがあったとします

sqlite> .tables
comments posts

む、sqlite3には mysql とかの describe 相当のコマンドが無いのだろうか。
とりあえずデータを突っ込んだ select で勘弁してね。

id|title|body|created_at|updated_at
1|title1|body|2010-09-25 05:55:18.912592|2010-09-25 05:55:18.912592
2|title2|body|2010-09-25 05:55:31.281979|2010-09-25 05:55:31.281979

いわゆるブログのエントリ的なものを想定して、titleとbodyっていうカラムがある。
そして、その各エントリにcommentが付く。

id|post_id|name|body|created_at|updated_at
1|1|hogehoge|comment1|2010-09-25 05:57:32.057127|2010-09-25 05:57:32.057127
2|1|hogehoge|comment2|2010-09-25 05:57:39.476946|2010-09-25 05:57:39.476946
3|1|hogehoge|comment3|2010-09-25 05:57:42.828758|2010-09-25 05:57:42.828758
4|2|unko|comment1|2010-09-25 05:57:53.740980|2010-09-25 05:57:53.740980
5|2|hogehoge|comment2|2010-09-25 05:58:03.020882|2010-09-25 05:58:03.020882

コメントには、対象となる post_id をもって紐付けさせる。

モデルでの関連付け

vim app/models/post.rb

has_manyを付ける

class Post < ActiveRecord::Base
  has_many :comments
end

rails console で以下のように試すと、コメントデータも取れる。

Post.find(1).comments
=> [#, #, #]

投稿メッセージにコメント数をつけたい

いわゆる commnet(1) とかをつけたい場合ね。
上記が試せていれば、

Post.find(1).comments.length

とかで取れる訳だけど、json などで渡すときに不都合ですよね。

まず、モデルにメソッドを定義する

一応、何回も呼ばれたときの為にキャッシュしておく。

class Post < ActiveRecord::Base
  has_many :comments

  def comment_count
    @comment_count ||= comments.length
  end
end

rails console で確認してみよう。

ruby-1.9.2-head > Post.find(1).comment_count
=> 3

おお、できてる。

to_json(to_xml)でメソッド呼び出しをする

:methods オプションで呼べる。

ruby-1.9.2-head > puts post.to_json(:methods => :comment_count)
{"post":{"body":"body","created_at":"2010-09-25T05:55:18Z","id":1,"title":"title1","updated_at":"2010-09-25T05:55:18Z","comment_count":3}}

整形するとこんな感じで、最後に comment_count っていうのが付く

{
    post: {
        body: body (string)
        ,created_at: 2010-09-25T05:55:18Z (string)
        ,id: 1 (number)
        ,title: title1 (string)
        ,updated_at: 2010-09-25T05:55:18Z (string)
        ,comment_count: 3 (number)
    }
}

整形は例のごとく JSON整形 を使った。
ちなみに、:methods で複数のメソッドを呼びたい場合は [:method名, :method名]のような感じで配列にすると良い。

これで

データを弄り回さずに出力用の形式に整形できますね。
enjoy!