courses#create 送出表單
編輯 spec/controllers/courses_controller_spec.rb
,加入另一段 Test。
你可以注意到,在這裡我們並不是使用之前常用的 create(:course)
,而是使用 build(:course)
。因為這個測試要求的是要先產生一個未儲存的 course 對象,然後再透過 POST 傳送 course 的 attributes (FactoryGirl.attributes_for
) 過去儲存。
describe "POST create" do
it "create a new course record" do
course = build(:course)
expect do
post :create, params: { :course => attributes_for(:course) }
end.to change{ Course.count }.by(1)
end
it "redirects to courses_path" do
course = build(:course)
post :create, params: { :course => attributes_for(:course) }
expect(response).to redirect_to courses_path
end
end
值得注意的是,因為 course 是我們 fake 出來的,所以我們很難以實際的手段(如比對內容)去偵測是否物件產生成功。所以我們這裡用了另外一種 RSpec 的 syntax,去測試有沒有產生紀錄成功(偵測 Course 增加的數量有沒有 +1)。
$ rspec spec/controllers/courses_controller_spec.rb
......FF
Failures:
1) CoursesController POST create create a new course record
Failure/Error: post :create, params: { :course => attributes_for(:course) }
AbstractController::ActionNotFound:
The action 'create' could not be found for CoursesController
2) CoursesController POST create redirects to courses_path
Failure/Error: post :create, params: { :course => attributes_for(:course) }
AbstractController::ActionNotFound:
The action 'create' could not be found for CoursesController
Finished in 0.04829 seconds (files took 1.15 seconds to load)
2 examples, 2 failures
Failed examples:
rspec ./spec/controllers/courses_controller_spec.rb:61 # CoursesController POST create create a new course record
rspec ./spec/controllers/courses_controller_spec.rb:69 # CoursesController POST create redirects to courses_path
補上 action
在 app/controllers/courses_controller.rb
加入 create
這個 action
def create
@course = Course.new(course_params)
@course.save
redirect_to courses_path
end
private
def course_params
params.require(:course).permit(:title, :description)
end
$ rspec spec/controllers/courses_controller_spec.rb
........
Finished in 0.08765 seconds (files took 1.14 seconds to load)
8 examples, 0 failures
限制:如果生 Course 時沒打標題,則不能儲存
不過這也許不符合你原本設計 Application 的慣例,通常我們的設計的習慣應該是,如果在 create
這個 action 儲存失敗,則退回 new
action;儲存成功則產生一筆紀錄,再回到 courses_path
,也就是表單有填錯的數據,退回繼續填寫表單。
怎樣才能儲存失敗呢?
不如我們就來限制,如果生 Course 時沒打標題,則不能儲存。
讓我們來修改測試變成以下:
describe "POST create" do
it "doesn't create a record when course doesn't have a title" do
expect do
post :create, params: { course: { :description => "bar" }}
end.to change { Course.count }.by(0)
end
it "render new template when course doesn't have title" do
post :create, params: { course: { :description => "bar" } }
expect(response).to render_template("new")
end
it "create a new course record when course has title" do
course = build(:course)
expect do
post :create, params: { course: attributes_for(:course) }
end.to change { Course.count }.by(1)
end
it "redirects to courses_path when course has title" do
course = build(:course)
post :create, params:{ course: attributes_for(:course) }
expect(response).to redirect_to courses_path
end
end
$ rspec spec/controllers/courses_controller_spec.rb
......FF..
Failures:
1) CoursesController POST create doesn't create a record when course doesn't have a title
Failure/Error:
expect do
post :create, params: { course: { :description => "bar" }}
end.to change { Course.count }.by(0)
expected result to have changed by 0, but was changed by 1
# ./spec/controllers/courses_controller_spec.rb:62:in `block (3 levels) in <top (required)>'
2) CoursesController POST create render new template when course doesn't have title
Failure/Error: expect(response).to render_template("new")
expecting <"new"> but was a redirect to <http://test.host/courses>
# ./spec/controllers/courses_controller_spec.rb:70:in `block (3 levels) in <top (required)>'
Finished in 0.11221 seconds (files took 1.16 seconds to load)
10 examples, 2 failures
Failed examples:
rspec ./spec/controllers/courses_controller_spec.rb:61 # CoursesController POST create doesn't create a record when course doesn't have a title
rspec ./spec/controllers/courses_controller_spec.rb:67 # CoursesController POST create render new template when course doesn't have title
然後我們要變更 controller 的內容,以及加上 Course model 的 title
限制:
修改 app/controllers/courses_controller.rb
中 create
這個 action
改成以下內容
def create
@course = Course.new(course_params)
if @course.save
redirect_to courses_path
else
render :new
end
end
修改 app/models/course.rb
,限制 course 一定要有標題
class Course < ActiveRecord::Base
validates :title, presence: true
end
這樣測試就會通過了!