modelの追加

というワケで、昨日の続きをやる。今日は、「つぶやき」アプリを改修してみよう(前編) − @ITの内容を、3rdRailを使わないでコマンドラインで実施。

hitokotoの編集

昨日の時点で一点、忘れていた。3rdRailでモデル作成の際に、hitokotoに「必須」のチェックを入れているのだが、おそらく、それに対応するのが、これ。

% cat app/models/hitokoto.rb 
class Hitokoto < ActiveRecord::Base
 validates_presence_of :hitokoto
end

app/models/hitokoto.rb に、「validates_presence_of :hitokoto」を追加する。

modelの追加: user

userモデルを追加する。「つぶやき」アプリを改修してみよう(前編) − @ITによると、気になることが書いてある。

今回は「生成されたリソースのスカフォルドを作成する」チェックを外しておくこととします

「つぶやき」アプリを改修してみよう(前編) − @IT

要するに、./script/generate scaffoldを使わないということだと思うんだけど、さて。

% ./script/generate --help
Usage: ./script/generate generator [options] [args]
.....(中略)...
Installed Generators
 Builtin: controller, helper, integration_test, mailer, metal, migration, model, observer, performance_test, plugin, resource, scaffold, session_migration
.....(以下略)...

このhelpを見て、何をすべきか分かる人は居ない気がする。やっぱり、railsに関して一通り説明してある本を買うべきだろうか?
modelを追加するけど、scaffoldじゃないという観点で考えると、ここで指定すべきoptionはおそらくmodelかresource。違いを知るには、sourceを見るか、、、と思ったけど、どのsourceを見れば良いのかさっぱり分からず断念。両方試してみることにした。

% ./script/generate model user name:string
     exists  app/models/                                               
     exists  test/unit/
     exists  test/fixtures/
     create  app/models/user.rb
     create  test/unit/user_test.rb
     create  test/fixtures/users.yml
     exists  db/migrate
     create  db/migrate/20090501102445_create_users.rb
% ./script/generate resource user name:string
     exists  app/models/
     exists  app/controllers/
     exists  app/helpers/
     create  app/views/users
     exists  test/functional/
     exists  test/unit/
     exists  test/unit/helpers/
 dependency  model
     exists    app/models/
     exists    test/unit/
     exists    test/fixtures/
     create    app/models/user.rb
     create    test/unit/user_test.rb
     create    test/fixtures/users.yml
     exists    db/migrate
     create    db/migrate/20090501103445_create_users.rb
     create  app/controllers/users_controller.rb
     create  test/functional/users_controller_test.rb
     create  app/helpers/users_helper.rb
     create  test/unit/helpers/users_helper_test.rb
      route  map.resources :users

自動生成されるファイルの構成から考えると、ここで使うべきoptionはmodelではなくresourceなんだろうな、と、推測。そして、生成されたuser.rbにはhitokoto.rb同様に「validates_presence_of :name」を追加しておく。

% cat app/models/user.rb
class User < ActiveRecord::Base
 validates_presence_of :name
end

Hitokotoモデルへの属性追加

続いて、HitokotoモデルがUserに属すことができるようにHitokotoモデルを改修しましょう。Hitokotoモデルから見て、どの Userに属しているかが分かればよいので、Userへの関連IDが必要になります。そこで、マイグレーション機能を使用して、Hitokotoモデルの属性としてUserモデルへの関連IDを追加します。

「つぶやき」アプリを改修してみよう(前編) − @IT

これに対応する。やっぱり、./script/generateで生成できるんだろうか?試しにやってみる。

% ./script/generate migration AddUserIdToHitokotos user_id:integer           
     exists  db/migrate
     create  db/migrate/20090501105327_add_user_id_to_hitokotos.rb
% cat db/migrate/20090501105327_add_user_id_to_hitokotos.rb 
class AddUserIdToHitokotos < ActiveRecord::Migration
 def self.up
   add_column :hitokotos, :user_id, :integer
 end

 def self.down
   remove_column :hitokotos, :user_id
 end
end

雛型はできたっぽいので、「つぶやき」アプリを改修してみよう(前編) − @ITに書かれている通りに、追記する。

% cat db/migrate/20090501105327_add_user_to_hitokotos.rb 
class AddUserIdToHitokotos < ActiveRecord::Migration
 def self.up
   add_column :hitokotos, :user_id, :integer, :null => false, :default => 0
 end
 
 def self.down
   remove_column :hitokotos, :user_id
 end
end

ここで、DBのmigrationをしておく。

% rake db:migrate
(in /Users/fukuit/Projects/tsubuyaki)
==  CreateUsers: migrating ====================================================
-- create_table(:users)
  -> 0.0022s
==  CreateUsers: migrated (0.0025s) ===========================================
 
==  AddUserIdToHitokotos: migrating ===========================================
-- add_column(:hitokotos, :user_id, :integer)
  -> 0.0012s
==  AddUserIdToHitokotos: migrated (0.0015s) ==================================

unit test

この後、「つぶやき」アプリを改修してみよう(前編) − @ITでは、unit testのためのコード作成が続く。
test/fixtures/hitokotos.yml、test/fixtures/users.yml、test/unit/user_test.rb、test/unit/hitokoto_test.rbのファイルを「つぶやき」アプリを改修してみよう(前編) − @ITのように作成してから、テスト用のDBを作成する。

% rake db:test:prepare
(in /Users/fukuit/Projects/tsubuyaki)

railsでは、どうやってunit testを実施するのか?rakeで何かコマンドを入力するんだろうなぁ。例えば上述のように、DBに対してテスト用のデータを準備するのが、「rake db:test:prepare」だっていうことは、rakeのoptionは英語っぽく複数の単語を「:」で繋げば良さそうだ。まずは、テストをすることを指示して、それが結合テストじゃなくてunitだってことを指示すれば良いはず。というワケで、当てずっぽうにやってみる、それらしい結果が表示された。

% rake test:unit 
(in /Users/fukuit/Projects/tsubuyaki)
rake aborted!
Don't know how to build task 'test:unit'
 
(See full trace by running task with --trace)
% rake test:units
(in /Users/fukuit/Projects/tsubuyaki)
/usr/bin/ruby -I"/Users/fukuit/Projects/tsubuyaki/lib" -I"/Users/fukuit/Projects/tsubuyaki/test" "/usr/lib/ruby/gems/1.8/gems/rake-0.8.4/lib/rake/rake_test_loader.rb" "test/unit/helpers/users_helper_test.rb" "test/unit/helpers/hitokotos_helper_test.rb" "test/unit/user_test.rb" "test/unit/hitokoto_test.rb" 
Loaded suite /usr/lib/ruby/gems/1.8/gems/rake-0.8.4/lib/rake/rake_test_loader
Started
EE
Finished in 0.058168 seconds.
 
 1) Error:
test_Hitokotoが属すUserを取得できる(HitokotoTest):
NoMethodError: undefined method `user' for #<Hitokoto:0xb7d2ae58>
   /test/unit/hitokoto_test.rb:6:in `test_Hitokotoが属すUserを取得できる'
 
 2) Error:
test_Userに属すHitokotoを取得できる(UserTest):
NoMethodError: undefined method `hitokotos' for #<User:0xb7d1344c>
   /test/unit/user_test.rb:6:in `test_Userに属すHitokotoを取得できる'
 
2 tests, 0 assertions, 0 failures, 2 errors
rake aborted!
Command failed with status (1): [/usr/bin/ruby -I"/Users/fukuit/Projects/ts...]
 
(See full trace by running task with --trace)

どうやら「rake test:units」が正しいようだ。複数形なのね。

コードの修正

unit testの結果を受けて、「つぶやき」アプリを改修してみよう(前編) − @ITのように、app/models/hitokoto.rbとapp/models/user.rbを修正した上で、再びunit testを実行する。

% rake test:units
....(中略)...
Started
...
Finished in 0.061379 seconds.
 
2 tests, 2 assertions, 0 failures, 0 errors

無事、テスト通過。というワケで今日は、ここまで。