おいちゃんと呼ばれています

ウェブ技術や日々考えたことなどを綴っていきます

FactoryGirl で多対多のアソシエーションをつくる

FactoryGirl の公式 README 読んでも多対多のアソシエーションをつくる書き方が分からなくて、先日やっと分かったのでメモしておきます。

使用しているバージョンは下記のとおりです。

登場モデル

例として、Video, Tag, Tagging が登場します。文字だけじゃ分かりにくいから graph-easy さんの出番ですね。

+-------+  1:n    +---------+  n:1    +-----+
| Video | <=====> | Tagging | <=====> | Tag |
+-------+         +---------+         +-----+
  • Video has_many taggings
  • Video has_many tags, through taggings
  • Tag has_many taggings
  • Tag has_many videos, through taggings
  • Tagging belongs_to video
  • Tagging belongs_to tags

FactoryGirl.define の中で多対多をつくる

FactoryGirl.define の中で多対多をつくるときは下記のような感じ。

FactoryGirl.define do
  factory :tag do
    name '喪服'
  end

  factory :video do
    title 'あなた、許して'

    after(:create) do |video|
      create(:tag, videos: [video])
    end
  end
end

もう少し実践的に書くと、実際のテストにはアソシエーションがない場合の video も必要なので、下記のようにネストさせたりしています。あと、シーケンス使ったりとか。

FactoryGirl.define do
  factory :tag do
    sequence(:name) { |n| "喪服#{n}" }
  end

  factory :video do
    sequence(:title) { |n| "あなた、許して#{n}" }

    factory :video_with_tags do
      after(:create) do |video|
        create(:tag, videos: [video])
      end
    end
  end
end

テストの中で多対多をつくる

多対多の関連をテストの中でつくりたいときもありますよね。下記のように書きます。

let(:tag1) { create(:tag) }
let(:tag2) { create(:tag) }
let!(:video) { create(:video, tags: [tag1, tag2]) }

before do
  visit videos_path
end

it '動画に関連するタグが表示される' do
  expect(page).to have_css(".tag", text: tag1.name)
end

おまけ - FactoryGirl. を省略する

なお、spec/spec_helper.rb に下記を記述しておくと、

RSpec.configure do |config|
  config.include FactoryGirl::Syntax::Methods
end

毎回毎回 FactoryGirl.create(:video) と書かずに create(:video) でいけるよと、最近 @ さんに教えていただきました。べんり〜

参考

以上です。

factory_girl は公式 README がすごく丁寧に書かれているので、多対多以外のことは、基本的にそちらを参照すればよいと思うのですが、とりあえず基本的なことを日本語で読みたい、という方には下記の記事がオススメです(下記記事にも多対多の書き方が載っていますが、今回紹介している書き方とは異なります)

ではでは。