Rspecでテストを書いているとき、下記の実装に関してpathの引数にtask.project
が使われていることに疑問を感じておりました。
describe 'Task詳細' do
context '正常系' do
it 'Taskが表示されること' do
visit project_task_path(task.project, task)
#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
#前提条件
taskとprojectがassociationの関係を持つ。
class project < ApplicationRecord
has_many tasks
end
class Task < ApplicationRecord
belongs_to :project
end
#考え方
まず考えるべきなのが、どのようなURLが生成されるべきかということ。
ここではTaskの詳細画面なのでURL/project/id/task/id/show
となるべきですね。
次にtaskとprojectがassociationの関係を持つということ。
class project < ApplicationRecord
has_many tasks
end
class Task < ApplicationRecord
belongs_to :project
end
これによりtaskはproject(親)のidを持つことになります。
実際にpathの引数のレコードを調べるとこんな感じ。
(byebug) project
#<**Project id: 1**, name: "dolorum", status: "todo", release_date: "2019-05-24", created_at: "2021-06-28 14:23:59", updated_at: "2021-06-28 14:23:59">
(byebug) task
#<Task id: 3, title: "Task", status: "done", deadline: "2019-10-17 15:00:00", completion_date: nil, description: nil, **project_id: 2**, created_at: "2021-06-22 10:38:01", updated_at: "2021-06-22 10:38:01">
(byebug) task.project
#<**Project id: 2**, name: "repudiandae", status: "todo", release_date: "2019-11-05", created_at: "2021-06-22 10:38:01", updated_at: "2021-06-22 10:38:01">
注目すべきはproject_id
****の値。
project_id: 1
に対しtaskはproject_id: 2
を持っていますね。
これはassociationの関係とは言えません。
実際project_task_path(project, task)
でもURL自体は生成されますが、これではproject_id
が異なるため、生成されるURLのidはassociationの関係ではなくなってしまいます。
project_task_path(project, task)
=> /project/1/task/3
project_task_path(task.project, task)
のようにしてproject(親)のidをtask.project
の返り値から取得することで、生成されるURLはassociationの関係を保つことができます。
project_task_path(task.project, task)
=> /project/2/task/3
#引数の順番を入れ替てみる
以下のような結果から、pathの引数はassociationで定義したことなど関係なく、引数に指定した順番の通りにidを渡すようです。
project_task_path(task.project, task)
=> /project/2/task/3
# 引数の順番を入れ替えた結果
project_task_path(task, task.project)
=> /project/3/task/2
なので、引数を指定する際は定義したassociationの関係や、実際のブラウザの挙動を意識して、引数を指定してあげる必要があります。