Wavesを試してみる - Model編

Tsukasa OISHI

 引き続きWavesを試してみます。
 チュートリアルによると、entryに1:nでcommentモデルとの関連付けをしています。
 まずはCommentsテーブルのmigrationを作成します。

rake schema:migration name=add_comments

で、schema/migrations/002_add_comments.rbを編集。

class AddComments < Sequel::Migration

  def up
    create_table :comments do
      primary_key :id
      foreign_key :entry_id, :table => :entries
      text :name
      text :email
      text :content
      timestamp :created_on
    end
  end

  def down
    drop_table :comments
  end

end

 そういえば、RailsではDBレベルでforeign_keyをあまりつけてないな。あと、created_onはSequelによって自動的に時刻が入るよう。Railsでいうcreated_atだね。created_onだと日付しか入らないみたいな感じがしてしまうのは、Railsの使いすぎか。ちなみにSequelというのはORMです。
 migrateをかましたら、Entryモデルを作成します。ていうか、今まで存在しなかったのかよ。デフォルトの動作がWavesの中で定義されていて、それ以外のことをやりたくなったときにはじめてコードを書くのかな。

rake generate:model name=entry

で、models/entry.rbが作成される。

module Blog
  module Models
    class Entry < Sequel::Model(:entries)
      before_save do
        set(:updated_on => Time.now) if columns.include? :updated_on
      end
    end
  end
end

before_saveはRailsと一緒かな。テーブルがupdated_onを持っていたら更新してくれるみたい。created_onはSequelでやってくれるのに、updated_onは自前でやるのか。中途半端だなあ。Wavesが勝手にコード吐いてくれるけど。
で、models/default.rbの中身がこれと一緒になっている。明示的にモデルを作成しなかったときは、default.rbが使われるんだな。たぶん。
さて、models/entry.rbにcommentmモデルとの関連付けを定義しましょう。

one_to_many :comments, :from => Blog::Models::Comment, :key => :entry_id

こいつをbefore_saveの下に追加します。Railsでいうところのhas_manyと一緒だね。相手のモデルと参照キーを指定してやんないといけない。fromって、なんだかぼくの認識だと参照先みたいな感じがしてしまう。
つづいてcommentモデルを作成する。

 rake generate:model name=comment

models/comment.rbは

module Blog
  module Models
    class Comment < Sequel::Model(:comments)      
      before_save do
        set(:updated_on => Time.now) if columns.include? :updated_on
      end
      one_to_one :entry, :from => Blog::Models::Entry
    end
  end
end

one_to_oneはRailsでいうbelongs_toだな。ここでのfromは違和感がない。

さて、viewのほうにコメントを追加してみます。チュートリアルからちょっとアレンジしてみます。templates/entry/show.mabは

layout :default, :title => @entry.title do
  a "すべて見る", :href => '/entries'

  h1 @entry.title
  textile @entry.content

  h2 "コメント"
  view :comment, :add, :entry => @entry
  view :comment, :list, :comments => @entry.comments
end

こんな感じ。見てわかるように、@entry.commentsみたいな感じでAR的にリレーション先へアクセスできるようです。
さて、add.mabとlist.mabをtemplates/commentディレクトリ下に作ります。
templates/comment/add.mab

form :action => "/comments", :method => 'POST' do
  input :type => :hidden, :name => 'comment.entry_id', :value => @entry.id
  label "名前"; br
  input :type => :text, :name => 'comment.name'; br
  label "Email"; br
  input :type => :text, :name => 'comment.email'; br
  label "コメント"; br
  textarea :name => 'comment.content', :rows => 10, :cols => 80; br
  input :type => :submit, :value => "書き込み"
end

POST先のURLが/commentsになっている。RailsみたいなURL(/entries/:id/comments)じゃないね。かわりに、hidden fieldを持っていて、そこにentry_idを入れている。これだと、URLはシンプルになっていいかも。REST的にはRailsの方が正しい気もするんだけど。
それから、templates/comment/list.mab

@comments.sort_by( &:created_on ).each do |comment|
  name = ((comment.name.nil? or comment.name.empty?) ? "通りすがり" : comment.name)
  p %Q|#{name} #{comment.created_on.strftime("%Y-%m-%d %H:%M")}|
  textile comment.content
end

チュートリアルのコードはわかりにくくて好きじゃない感じだったので書き直してみました。

で、実際にコメントを書いてみると、/comment//editorなんていうURLに飛ばされるのだけど、当然404になる。いよいよルーティングを定義する必要があるみたい。続きはまた今度にしよう。