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.rbcreate 這個 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

這樣測試就會通過了!

results matching ""

    No results matching ""