更新時刻の設定をコントローラからモデルへ
2006-10-04
さっきの例では、ページの更新時刻をコントローラー (note_controller.rb) で設定していた。 でもよく考えると、コントローラのアクションが増えるごとに、同じような処理を書かないといけない。 既に、 NoteController の create と update で、同じ処理(@page.updated = Time.now)が書かれているし。 コントローラをシンプルに書けるのが Rails のいい所らしいので、処理をコントローラ (note_controller.rb) からモデル (page.rb) へと移す。
Rails のモデル (ActiveRecord::Base) にはコールバックという仕組みがあって、生成や更新時などに実行したい処理を登録できるようになっている。 生成時 (before_create) と更新時 (before_save) にそれぞれ現在時刻を設定する処理を追加した。
Index: app/models/page.rb
===================================================================
--- app/models/page.rb (リビジョン 2)
+++ app/models/page.rb (作業コピー)
@@ -1,4 +1,7 @@
class Page < ActiveRecord::Base
+ before_create {|model| model.created = Time.now }
+ before_save {|model| model.updated = Time.now }
+
def title
body.each {|title| return title.chomp }
end
そして、先ほど追加したコントローラ (note_controller.rb) の create と update の処理を削除する。
Index: app/controllers/note_controller.rb
===================================================================
--- app/controllers/note_controller.rb (リビジョン 2)
+++ app/controllers/note_controller.rb (作業コピー)
@@ -23,8 +23,6 @@
def create
@page = Page.new(params[:page])
- @page.created = Time.now
- @page.updated = Time.now
if @page.save
flash[:notice] = 'Page was successfully created.'
redirect_to :action => 'list'
@@ -39,7 +37,6 @@
def update
@page = Page.find(params[:id])
- @page.updated = Time.now
if @page.update_attributes(params[:page])
flash[:notice] = 'Page was successfully updated.'
redirect_to :action => 'show', :id => @page
これでもちゃんと、生成時刻と更新時刻が設定されていることを確認。 うん。大丈夫そうだ。
リポジトリへも登録しておいた。
さらに簡略化
さらに調べてみると、モデルに created_on と updated_on というカラムを作っておくと、生成時刻と更新時刻を Rails が自動的にセットしてくれるらしい。 惜しい…「_on」が足りなかった。 でも仮に、この機能を知らずに created_on, updated_on なんて名前を付けていたら、それはそれで不思議な挙動に悩んでいただろうな。 モデルのコールバックの使い方も覚えられたし、まぁいいか。
とりあえず、 created を created_on に、 update を updated_on に変更する。 まずはデータベースのマイグレーションから。
$ vi db/migrate/003_rename_update_of_page.rb
class RenameUpdateOfPage < ActiveRecord::Migration
def self.up
remove_index :pages, :created
remove_index :pages, :updated
rename_column :pages, :created, :created_on
rename_column :pages, :updated, :updated_on
add_index :pages, :created_on
add_index :pages, :updated_on
end
def self.down
remove_index :pages, :created_on
remove_index :pages, :updated_on
rename_column :pages, :created_on, :created
rename_column :pages, :updated_on, :updated
add_index :pages, :created
add_index :pages, :updated
end
end
この内容でマイグレーションを実行すると、なぜか既存の時刻の内容が消えてしまった (created_on と updated_on が空になった) 。 まぁ、今はサンプルデータだから支障は無いんだけど。
他にもモデル・コントローラ・ビューを修正する。 Webブラウザからアクセスして、ちゃんと更新順に並ぶことを確認した。