更新時刻の設定をコントローラからモデルへ
さっきの例では、ページの更新時刻をコントローラー (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ブラウザからアクセスして、ちゃんと更新順に並ぶことを確認した。