使用者新增 course 的話,必須要跟 user 做關聯
首先幫 context "when course has title" do
場景新增一支測試:
describe "POST create" do
let(:user) { create(:user) }
before { sign_in user }
context "when course doesn't have title" do
...
end
context "when course has title" do
...
it "redirects to courses_path" do
...
end
it "creates a course for user" do
course = build(:course)
post :create, params: { course: attributes_for(:course) }
expect(Course.last.user).to eq(user)
end
end
end
錯誤訊息
$ rspec spec/controllers/courses_controller_spec.rb
...........F..........
Failures:
1) CoursesController POST create when course has title creates a course for user
Failure/Error: expect(Course.last.user).to eq(user)
NoMethodError:
undefined method `user' for #<Course:0x007fba9f993110>
Finished in 0.22045 seconds (files took 1.94 seconds to load)
22 examples, 1 failure
Course 跟 user 還沒有關聯(Association)存在。
先新增一個關聯的測試,使用 Shoulda Matchers 的 belong_to:
修改 spec/modes/course_spec.rb
RSpec.describe Course do
it { is_expected.to validate_presence_of(:title) }
it { is_expected.to belong_to(:user) }
end
跑測試:
$ rspec spec/models/course_spec.rb
.F
Failures:
1) Course should belong to user
Failure/Error: it { is_expected.to belong_to(:user) }
Expected Course to have a belongs_to association called user (no association called user)
Finished in 0.02089 seconds (files took 1.98 seconds to load)
2 examples, 1 failure
接著加上關聯。
修改 app/modesl/course.rb
class Course < ActiveRecord::Base
belongs_to :user
validates :title, presence: true
end
$ rspec spec/models/course_spec.rb
.F
Failures:
1) Course should belong to user
Failure/Error: it { is_expected.to belong_to(:user) }
Expected Course to have a belongs_to association called user (Course does not have a user_id foreign key.)
# ./spec/models/course_spec.rb:5:in `block (2 levels) in <top (required)>'
Finished in 0.02253 seconds (files took 1.72 seconds to load)
2 examples, 1 failure
Failed examples:
rspec ./spec/models/course_spec.rb:5 # Course should belong to user
缺少外鍵 user_id
。
新增 migration
$ rails g migration add_user_id_to_courses
class AddUserIdToCourses < ActiveRecord::Migration[5.0]
def change
add_column :courses, :user_id, :integer
add_index :courses, :user_id
end
end
通常加上外鍵時會順便加上 index,加快取得關聯物件的速度。
執行 rake db:migrate
遷移數據庫。
Model 的 spec 跑通了:
$ rspec spec/models/course_spec.rb
..
Finished in 0.01558 seconds (files took 1.67 seconds to load)
2 examples, 0 failures
course factory 補上 user
接著跑 controller spec 發現錯誤全都是:
Failure/Error: course = create(:course)
ActiveRecord::RecordInvalid:
Validation failed: User must exist
這是因為現在 course 需要 user 才可以創建,補上 user 到 Course Factory:
diff --git a/spec/factories.rb b/spec/factories.rb
index 54f2595..07911dc 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -10,5 +10,6 @@ FactoryGirl.define do
factory :course do
title "Course Name"
description "Description."
+ user
end
end
加上 user
到 factory :course do
區塊。
再次執行測試可以看到只剩下三個錯誤:
$ rspec spec/controllers/courses_controller_spec.rb
.........FFF..........
Failures:
1) CoursesController POST create when course has title create a new course record
Failure/Error:
expect do
post :create, params: { course: attributes_for(:course) }
end.to change { Course.count }.by(1)
expected result to have changed by 1, but was changed by 0
2) CoursesController POST create when course has title redirects to courses_path
Failure/Error: expect(response).to redirect_to courses_path
Expected response to be a <3XX: redirect>, but was a <200: OK>
3) CoursesController POST create when course has title creates a course for user
Failure/Error: expect(Course.last.user).to eq(user)
NoMethodError:
undefined method `user' for nil:NilClass
Finished in 0.29536 seconds (files took 1.69 seconds to load)
22 examples, 3 failures
創建 course 時少給了 user,在 Controller 補上。
修改 app/controller/courses_controller.rb 中的 create
diff --git a/app/controllers/courses_controller.rb b/app/controllers/courses_controller.rb
index eb61256..3e440da 100644
--- a/app/controllers/courses_controller.rb
+++ b/app/controllers/courses_controller.rb
@@ -15,6 +15,7 @@ class CoursesController < ApplicationController
def create
@course = Course.new(course_params)
+ @course.user = current_user
if @course.save
redirect_to courses_path
補上 @course.user = current_user
即可。