factory_girlを試してみた。(その3)

factory_girlネタも今回で3回目。今回は関連について書いていきます。

前々回はこちら
前回はこちら

使用したバージョンなど

今回使用したバージョンは

  • factory_girl_rails 3.0.0
  • factory_girl 3.0.0

を使用しています。

関連データの記述方法

postsテーブルを次のように作成して、userへの参照を持たせるようにします。

class CreatePosts < ActiveRecord::Migration
  def change
    create_table :posts do |t|
      t.string :title
      t.text :body
      t.references :user

      t.timestamps
    end
    add_index :posts, :user_id
  end
end

また、Postモデルにbelongs_toを書いておきます。

class Post < ActiveRecord::Base
  belongs_to :user
end

これで準備OK。factoriesディレクトリの下にposts.rbを次のように記述します。

FactoryGirl.define do
  factory :post do
    title "MyString"
    body "MyText"
    user
  end
end

userと書かれている行がpostデータとの関連が張っているところです。関連名=factory_girlの定義名の場合は、特に名前を指定せずとも適切な物(今回は、定義名userのもの)が指定されたことになります。

作成してみましょう。

irb(main):002:0> p = FactoryGirl.build(:post)
   (0.1ms)  begin transaction
  SQL (0.7ms)  INSERT INTO "users" ("created_at", "email", "name", "updated_at") VALUES (?, ?, ?, ?)  [["created_at", Fri, 04 May 2012 07:59:47 UTC +00:00], ["email", "hoge@example.com"], ["name", "User1"], ["updated_at", Fri, 04 May 2012 07:59:47 UTC +00:00]]
   (3.6ms)  commit transaction
=> #<Post id: nil, title: "MyString", body: "MyText", user_id: 8, created_at: nil, updated_at: nil>
irb(main):003:0> 

新しくUserが作成され、その作られたUserに対して関連を貼ったPostデータが作成されます。Userデータはテーブルに保存されますが、Postデータは(FactoryGirl.buildを使っているため)保存されません。

関連名≠factory_girlの定義名の場合は、association ... といったちょっと面倒くさいことを書く必要があります。

FactoryGirl.define do
  factory :post2, :class => Post do
    title "post2 sample title"
    body "post2 sample body"
    association :user, factory: :user4
  end
end

こう書いておいて、user4の定義は、

FactoryGirl.define do
  sequence(:sequence_string) { |n| "email#{n}@example.com" }

  factory :user4, :class => User do
     name { FactoryGirl.generate(:sequence_string) }
     email { "#{name}@exmaple.com" }
  end

end

と書いておくと、

irb(main):001:0> p = FactoryGirl.build(:post2)
   (0.1ms)  begin transaction
  SQL (47.6ms)  INSERT INTO "users" ("created_at", "email", "name", "updated_at") VALUES (?, ?, ?, ?)  [["created_at", Fri, 04 May 2012 08:17:39 UTC +00:00], ["email", "email1@example.com@exmaple.com"], ["name", "email1@example.com"], ["updated_at", Fri, 04 May 2012 08:17:39 UTC +00:00]]
   (3.5ms)  commit transaction
=> #<Post id: nil, title: "post2 sample title", body: "post2 sample body", user_id: 9, created_at: nil, updated_at: nil>
irb(main):002:0> 

上の例のように、Userにはuser4で定義したデータで関連が貼られます。

まとめ

というわけで、まだまた機能はありますが、ひと通りの使い方は書けたかなと思います。

で、ここからはfactory_girlの使い方で気がついたプチノウハウなどを。

  • データの定義についてはかなり便利。
  • 一個一個のデータに名前をつけるのは結構だるい。権限ロールごとに10ユーザーを作るってことを考えると、1ユーザーごとに定義するのではなくて、権限ロールごとに作ったほうが良い。で、ユーザーをユニークにするのはsequenceなどを使う。
  • いわゆるマスタデータ(都道府県一覧とか)をfactory_girlでつくろうとしない。factory_girlの処理もそれなりに時間がかかるので、seed.rbやFixtureで定義したほうが良いかと。

というわけで、3回にわたって書いてきましたfactory_girlの使い方、これにて終了。