##associationとは
関連するデータを一緒に作成してくれるメソッド。
例としてtask
を作成する際に、project
も作成必須の場合でassociation
無しのコードを見てみると、
#associationを使わない方法
let(:project) { create(:project) }
let(:task) { create(:task,project: project) }
このようにtask
とproject
の両方のテストコードを記述しなければならない。
本来なら、さらに関連するテーブルが増えていくので、後々しんどくなる。
これを解決するのがassociation
メソッド。
##associationの記入法
association
の記述の仕方は簡単で、 Factory
にアソシエーションするものを記述するだけである。
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
データも作成され、project
のproject_id
も自動でid
が入るようになる。
-association
で作成するデータが被る場合-
例えばlike
データを作成する時、以下のようにするとtask
データが2つ作られてしまう。
FactoryBot.define do
factory :like do
# taskには「association :project」が宣言されているため
# projectのデータが2つ作られることになる。
association :project
association :task
end
end
task
で作成されたproject
を使えば解決する。
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の使い方