2011年9月17日土曜日

Rails3を初歩から学ぶ #21 関連モデルの作成

この一連のエントリは
Ruby on Rails 3 Tutorial: Learn Rails by Example (Addison-Wesley Professional Ruby Series)
で参考に学んだことを凝縮してお送りしています。

今回からはユーザーがお気に入りとして登録する対象となる映画情報を作成していきます。
まずはMovieモデルを用意しましょう。
rails generate model Movie name:string
rake db:migrate
rake db:test:prepare
映画の名前だけをフィールドに持ったテーブルです。
このMovieモデルにおけるvalidatesの実装やテストコードについては省略します。
またコントーラ、ビュー、ルート定義もUserモデルと同じ(パスワードの暗号化が無い分、こちらの方がシンプル)なので説明は省略します。
Userモデルを参考にしながら作ってみてください。

そしてこの段階でUserとMovieというテーブルが出来ました。
ここで例えばuser.moviesとすると、そのuserインスタンスが好きだと言っている映画のタイトルが配列で取れる、なんてことを実現したいとします。
また同時にmovie.usersとすると、そのmovieのことを好きだと言っているユーザーの配列が取れる、ということも実現したいのです。

このようなとき、「userが好きだといっているmovie」を表すテーブルを用意します。
スキーマとしては以下のようになります。
ユーザーIDinteger
映画IDinteger
これを「Fanモデル」としましょう。このFanモデルをUserモデルと、さらにFanモデルとMovieモデルを紐づけます。そうするとFanモデルを経由してUserモデルとMovieモデルが対応付けられます。
まあとにかく、やってみましょう。
最初にFanテーブルをつくります。

>rails generate model Fan user_id:integer movie_id:integer
ユーザーIDと映画IDにはインデックスを設定したいので、生成されたマイグレーションファイルを編集します。db/migrate/XXXXX_create_fans.rb を編集します。
class CreateFans < ActiveRecord::Migration
def self.up
create_table :fans do |t|
t.integer :user_id
t.integer :movie_id
t.timestamps
end
add_index :fans, :user_id
add_index :fans, :movie_id

end
def self.down
drop_table :fans
end
end
赤字の部分を追加します。
「rake db:migrate」でマイグレーションして、「rake db:test:prepare」で検査環境に反映させます。そしてこのfan.rb用の試験コードを作成しましょう。
# -*- coding: utf-8 -*-
require 'spec_helper'
describe Fan do
before(:each) do
@user = Factory(:user)
@movie = Factory(:movie)
@fan = @user.fans.build(:movie_id => @movie.id)
end
it "登録できること" do
@fan.save!
end
describe "Userオブジェクトからのアクセス" do
before(:each) do
@fan.save
end
it "fanインスタンスからuserインスタンスを取得できること" do
@fan.user.should == @user
end
it "fanインスタンスからmovieインスタンスを取得できること" do
@fan.movie.should == @movie
end
end #Userオブジェクトからのアクセス
describe "バリデーションの検証" do
it "user_idが必要" do
@fan.user_id = nil
@fan.should_not be_valid
end
it "movie_idが必要" do
@fan.movie_id = nil
@fan.should_not be_valid
end
end #バリデーションの検証
end


映画情報に関するファクトリメソッドもUserモデルと同じように存在するもとしています。
buildメソッドは保存前のモデルオブジェクトを生成します。
buildメソッドで受け取ったインスタンスの「save!」メソッドを呼び出すことで検証しています。今まで使って来た「should」が使われていませんが、save!メソッドは失敗すると例外が発生するので、このままで問題ありません。
次にuser.moviesといった呼び出し方が出来るかどうかの検査項目をspec/model/user_spec.rbに追加します。
describe "fans" do
before(:each) do
@user = Factory(:user)
end
it "fansメソッドが機能すること" do
@user.should respond_to(:fans)
end
it "moviesメソッドが機能すること" do
@user.should respond_to(:movies)
end
end #fans
user.fansやuser.moviesといった呼び出し方が出来ることを検証しています。
同様にmoviesの検証も追加します。
describe "fans" do
before(:each) do
@movie = Factory(:movie)
end
it "fansメソッドが機能すること" do
@movie.should respond_to(:fans)
end
it "usersメソッドが機能すること" do
@movie.should respond_to(:users)
end
end #recommends
先ほどのUserモデル向けの検査と向きが逆方向になっただけで、ほぼ同じ内容です。
つまりmovie.fansやmovie.usersといった呼び出しの検証です。
この検査をパスするための実装は次回からとりかかります。

0 件のコメント:

コメントを投稿