1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

FactoryBotにおけるassociationとは

Posted at

##associationとは
関連するデータを一緒に作成してくれるメソッド。
例としてtaskを作成する際に、projectも作成必須の場合でassociation無しのコードを見てみると、

#associationを使わない方法
let(:project) { create(:project) }
let(:task) { create(:task,project: project) }

このようにtaskprojectの両方のテストコードを記述しなければならない。
本来なら、さらに関連するテーブルが増えていくので、後々しんどくなる。
これを解決するのがassociationメソッド。

##associationの記入法
associationの記述の仕方は簡単で、 Factoryにアソシエーションするものを記述するだけである。

factories/tasks.rb
FactoryBot.define do
  factory :task do
    title { 'Task' }
    content { 'content' }
    association :project
  end
end

次にspecファイルにて記入する。associationの有無は以下の通り。

#associationを使わない方法
  let(:project) { create(:project) }
  let(:task) { create(:task,project: project) }

#associationを使った方法
  let(:project) { create(:project) }
  let(:task) { create(:task) }

アソシエーションしているので、**let(:task) { create(:task) }**と記載することで、taskデータ作成と同時にprojectデータも作成され、projectproject_idも自動でidが入るようになる。

-associationで作成するデータが被る場合-
例えばlikeデータを作成する時、以下のようにするとtaskデータが2つ作られてしまう。

likes.rb
FactoryBot.define do
  factory :like do
    # taskには「association :project」が宣言されているため
    # projectのデータが2つ作られることになる。
    association :project
    association :task
  end
end

taskで作成されたprojectを使えば解決する。

likes.rb
FactoryBot.define do
  factory :like do
    association :project
    user { project.task }
  end
end

##associationをした事による引数に注意
例えば下記のようなテストコードがあったとする。この記述はassociationを使用していない記述である。

RSpec.describe 'Task', type: :system do
  let(:project) { create(:project) }
  let(:task) { create(:task,project: project) }
  describe 'Task詳細' do
    context '正常系' do
      it 'Taskが表示されること' do
        visit project_task_path(project, task)
        expect(page).to have_content(task.title)
        expect(page).to have_content(task.status)
        expect(page).to have_content(task.deadline.strftime('%Y-%m-%d %H:%M'))
        expect(current_path).to eq project_task_path(task.project, task)
      end
    end
  end
end

このコードをassociationを使って記述するとき、letの部分はlet(:task) { create(:task)}と書けば済むが、

**visit project_task_path(project, task)**の引数をこのままでは、
第1引数にtaskと結びついていないproject_idを呼び出す事になってしまう

第2引数のtaskに紐づくよう、第1引数はtask.projectにしなければならない。

# 上記のコードをassociationで記述した場合
RSpec.describe 'Task', type: :system do
  let(:project) { create(:project) }
  let(:task) { create(:task) } #ここと
  describe 'Task詳細' do
    context '正常系' do
      it 'Taskが表示されること' do
        visit project_task_path(task.project, task) #ここ
        expect(page).to have_content(task.title)
        expect(page).to have_content(task.status)
        expect(page).to have_content(task.deadline.strftime('%Y-%m-%d %H:%M'))
        expect(current_path).to eq project_task_path(task.project, task)
      end
    end
  end
end

##参考記事
【FactoryBot】associationの使い方

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?