← 上一章:Controller 下一章:CRUD 分解動作 - 簡易票選系統實作(下) →
CRUD 分解動作 - 簡易票選系統實作(上)
- 第 00 步 - 修改 Route
- 第 01 步 - 新增 Controller
- 第 02 步 - 新增 Model
- 第 03 步 - 新增 View
- 第 04 步 -「候選人列表」功能
- 第 05 步 -「新增候選人資料」功能 Part 1
- 第 06 步 -「新增候選人資料」功能 Part 2
- 第 07 步 -「編輯候選人資料」功能 Part 1
- 第 08 步 -「編輯候選人資料」功能 Part 2
- 第 09 步 -「編輯候選人資料」功能 Part 3
- 第 10 步 -「刪除候選人資料」功能
- 小結
CRUD 是 Create(新增), Read(讀取), Update(更新) 跟 Delete(刪除) 四個字的縮寫,對 Rails 來說,開發 CRUD 應用程式可以說是它的強項,甚至用 Scaffold 一行指令就搞定。第一次用 Scaffold 會感覺非常神奇,但對新手來說也不知道到底發生什麼事。所以接下來這個章節,我們將一步一步分解 CRUD 的各項動作,希望可以讓大家更了解 Rails 的一些慣例以及 Scaffold 到底做了什麼事。
實作:票選系統
我們將實作一個簡易的投票系統,藉此熟悉 Rails 的 MVC 運作方式以及表單處理。在開始前,先再次複習一下這張 MVC 的圖解:
當你填寫表單完成並按下送出後,表單會以 GET 或 POST 的方式傳送資料,Route 就會根據路徑以及動作(HTTP Verb)來決定這次的任務該由哪一個 Controller 的哪一個 Action 處理。
系統功能
- 可以新增、修改、刪除候選人資料(姓名、黨派、年齡、政見,以上資料都是必填欄位)。
- 可以投票給候選人並顯示該候選人得票數。
第 00 步 - 修改 Route
Route 是整個 Rails 應用程式的第一關,所以在思考要新增功能的時候,我通常第一步都是先想 Route 要怎麼規劃。因為要可以新增、修改、刪除候選人,所以我使用 resources
直接做出完整的 CRUD 路徑,範例如下:
# 檔案:app/config/routes.rb
Rails.application.routes.draw do
resources :candidates
end
這樣就可以做出以下的路徑:
$ bin/rails routes
Prefix Verb URI Pattern Controller#Action
candidates GET /candidates(.:format) candidates#index
POST /candidates(.:format) candidates#create new_candidate GET /candidates/new(.:format) candidates#new edit_candidate GET /candidates/:id/edit(.:format) candidates#edit
candidate GET /candidates/:id(.:format) candidates#show
PATCH /candidates/:id(.:format) candidates#update
PUT /candidates/:id(.:format) candidates#update
DELETE /candidates/:id(.:format) candidates#destroy
resources
方法可以幫忙做出 8 個路徑,分別對到新增、修改、刪除等 7 個 Action。Route 相關介紹請參閱第 11 章。
第 01 步 - 新增 Controller
有了路徑,知道要往哪邊去了,接下來就是把要去的地方完成。先使用 Rails 內建的產生器把 Controller 做出來:
$ bin/rails generate controller candidates
Running via Spring preloader in process 9314
create app/controllers/candidates_controller.rb
invoke erb
create app/views/candidates
invoke test_unit
create test/controllers/candidates_controller_test.rb
invoke helper
create app/helpers/candidates_helper.rb
invoke test_unit
invoke assets
invoke coffee
create app/assets/javascripts/candidates.coffee
invoke scss
create app/assets/stylesheets/candidates.scss
透過產生器指令,除了 Controller 本身以及 View 目錄外,還順便也幫忙產生相關的測試檔、JavaScript(CoffeeScript)、CSS(SCSS)檔案。因為檔案其實不多也不複雜,所以即使手工自己建立檔案也沒什麼太大的問題。
第 02 步 - 新增 Model
讓我們想一下這個候選人(Candidate)的 Model 要有哪些欄位:
欄位名稱 | 資料型態 | 說明 |
---|---|---|
name | 字串(string) | 候選人姓名 |
party | 字串(string) | 政黨 |
age | 數字(integer) | 年齡 |
politics | 文字(text) | 政見 |
votes | 數字(integer),預設值 0 | 得票數 |
候選人的資料表先大概這樣設計,但其實直接把「得票數」放在這裡不是很適當,應該另外開一個資料表來記錄得票過程,但這個功能會留到後面說明 Model 關連的時候再實作會更有感覺。讓我們先使用 Rails 的產生器來建立 Model 吧:
$ bin/rails generate model candidate name party age:integer politics:text votes:integer
Running via Spring preloader in process 10531
invoke active_record
create db/migrate/20170502075741_create_candidates.rb
create app/models/candidate.rb
invoke test_unit
create test/models/candidate_test.rb
create test/fixtures/candidates.yml
因為我們想要給得票數(votes
)的預設值設定成 0,但這件事沒辦法直接從產生器的指令完成,所以請先編輯 migration 檔,在 t.integer :votes
那行後面加上 default: 0
以設定這個欄位的預設值:
class CreateCandidates < ActiveRecord::Migration[5.0]
def change
create_table :candidates do |t|
t.string :name
t.string :party
t.integer :age
t.text :politics
t.integer :votes, default: 0
t.timestamps
end
end
end
最後,別忘了把 Migration 轉換成真正的表格:
$ bin/rails db:migrate
== 20170502075741 CreateCandidates: migrating =================================
-- create_table(:candidates)
-> 0.0012s
== 20170502075741 CreateCandidates: migrated (0.0013s) ========================
第 03 步 - 新增 View
有 Route、Controller 跟 Model 之後,接下來就要做頁面跟表單了。請先在 app/views/candidates
目錄下新增以下幾個檔案:
檔案名稱 | 用途 |
---|---|
index.html.erb | 全部候選人列表 |
new.html.erb | 新增候選人資料 |
edit.html.erb | 編輯候選人列表 |
Rails 目前沒有專門為 View 設計的產生器,所以上面這幾個檔案請自己手動新增檔案。
第 04 步 -「候選人列表」功能
「候選人列表」頁面要把所有候選人的資料從資料表抓出來,然後顯示在畫面上,所以這個步驟需要動到 Controller、View 以及 Model(不過事實上 Model 在這個步驟不需要做什麼事)。這個步驟需要先修改 Controller 跟 index.html.erb
頁面,先看一下 Controller:
# 檔案:app/controllers/candidates_controller.rb
class CandidatesController < ApplicationController
def index
@candidates = Candidate.all
end
end
這裡使用了 Model 的 all
類別方法取得所有資料,並存成 @candidates
實體變數,以便待會在 View 可使用。
注意事項:
- 像這樣取出來是一批資料的,慣例上都會使用複數名詞,例如
@candidates
或@users
。 - 除非必要,請盡量先使用區域變數而不要使用實體變數,以上面這個例子來說,因為稍後要在 View 使用
@candidates
變數所以才使用實體變數。
接下來修改 index.html.erb
:
<h1>候選人列表</h1>
<%= link_to "新增候選人", new_candidate_path %>
<table>
<thead>
<tr>
<td>候選人姓名</td>
<td>政黨</td>
<td>政見</td>
<td>得票數</td>
</tr>
</thead>
<tbody>
<% @candidates.each do |candidate| %>
<tr>
<td><%= candidate.name %>(年齡:<%= candidate.age %> 歲)</td>
<td><%= candidate.party %></td>
<td><%= candidate.politics %></td>
<td><%= candidate.votes %></td>
</tr>
<% end %>
</tbody>
</table>
這裡有幾個地方需要說明一下:
- 最上面的「新增候選人」連結,雖然可以使用一般的
<a href="...">..</a>
方式來寫,但在 Rails 裡更建議使用link_to
方法來產生連結。 - 中間的那段 Block 裡面的變數命名,慣例上會使用前面那個實體變數(
@candidates
)的單數名詞(candidate
)。 - 你有發現我們在這個檔案(index.html.erb)只有從
<h1>
開始寫,但檢視原始碼的時候卻發現<html>
、<title>
跟<body>
等標籤都有了嗎? 這個其實是 Rails 裡的 Layout 做的好事,會在後面章節有更詳細介紹。
啟動 Rails Server 看一下,現在的畫面應該會長得像這樣:
目前因為都還沒有資料所以一片空白很正常。
第 05 步 -「新增候選人資料」功能 Part 1
這個步驟比前面幾步麻煩一點,需要修改的地方主要是 Controller 跟 View。
先編輯 app/views/candidates/new.html.erb
,把新增資料的表單放在這個頁面:
<h1>新增候選人</h1>
<%= form_for(@candidate) do |f| %>
<%= f.label :name, "姓名" %>
<%= f.text_field :name %> <br />
<%= f.label :age, "年齡" %>
<%= f.text_field :age %> <br />
<%= f.label :party, "政黨" %>
<%= f.text_field :party %> <br />
<%= f.label :politics, "政見" %>
<%= f.text_area :politics %> <br />
<%= f.submit %>
<% end %>
<br />
<%= link_to '回候選人列表', candidates_path %>
這個 form_for
跟前個章節在介紹 BMI 計算機的 form_tag
有點類似,但更厲害一點。form_for
方法可以接一個 Model 物件參數,在這裡我們先傳一個名為 @candidate
的實體變數給它,待會在 Controller 再看看它是怎麼做出來的。在 form_for
方法後面的那個 Block 裡面的 f
變數,是一種 FormBuilder物件,可以透過這個物件上的 text_field
、text_area
或 submit
方法做出對應的 <input>
標籤。
接下來看一下 Controller:
class CandidatesController < ApplicationController
# .. [略] ..
def new
@candidate = Candidate.new
end
end
多加了一個 new
方法,裡面只放了簡單的一行,就是使用 Candidate
這個 Model 類別做出一個新的實體,並命名為 @candidate
實體變數,稍候供 View 使用。現在的畫面應該是這個樣子:
不怎麼美觀!沒關係,先把功能做出來,下個章節我們再來想辦法美化它。
在 Controller 的 new
方法裡設定的實體變數 @candidate
,就是要給剛剛前面 form_for
用的。form_for
除了可以產生 <form>
標籤之外,它的 action
,也就是當你按下送出按鈕要去的那個地方,會根據傳給它的這個物件是新的還是舊的而自己判斷。在這裡因為是剛剛才做出來的,form_for
會認為你現在是要做「新增」這件事。檢視一下原始碼,看一下 <form>
的那段:
<form class="new_candidate" id="new_candidate" action="/candidates" accept-charset="UTF-8" method="post">
因為它認為你是要「新增」,所以 action 的網址自動幫你設定成 /candidates
,並且使用 post
方法傳送。回想一下我們目前的 Route:
$ bin/rails routes
Prefix Verb URI Pattern Controller#Action
candidates GET /candidates(.:format) candidates#index
POST /candidates(.:format) candidates#create
new_candidate GET /candidates/new(.:format) candidates#new
edit_candidate GET /candidates/:id/edit(.:format) candidates#edit
candidate GET /candidates/:id(.:format) candidates#show
PATCH /candidates/:id(.:format) candidates#update
PUT /candidates/:id(.:format) candidates#update
DELETE /candidates/:id(.:format) candidates#destroy
對 /candidates
路徑使用 POST
方法,Route 會去找 candidates#create
處理。
咦?怎麼這麼巧?其實這不是巧合,這就是 Rails 的慣例。
第 06 步 -「新增候選人資料」功能 Part 2
既然知道這個表單按下送出之後會把資料拋給 Controller 的 create
方法,那就準備來「接球」吧:
class CandidatesController < ApplicationController
# .. [略] ..
def create
@candidate = Candidate.new(params[:candidate])
if @candidate.save
# 成功
redirect_to candidates_path, notice: "新增候選人成功!"
else
# 失敗
render :new
end
end
end
傳過來的那包資料會被收集在 params
這個特別的變數裡(正確來說 params 是一個方法),透過 params[:candidate]
可以取得前一個畫面拋過來那些欄位的資料,並且把它傳給 Candidate Model 的 new
方法以建立物件。
接下來,呼叫剛剛建立的物件的 save
方法準備存檔。如果存檔成功,便轉往候選人列表頁(redirect_to
),並帶有一提示訊息(Flash,後面的章節會再介紹)說「新增候選人成功!」;如果失敗,則重新 render 新增頁面,並顯示錯誤訊息。
看起來好像沒什麼問題,但當你按下新增之後會發生錯誤畫面如下:
這個 ActiveModel::ForbiddenAttributesError
錯誤訊息發生的原因,是因為我們試圖把 params[:candidate]
裡的資料一口氣塞進 Model 裡,這樣做會有安全上的問題,有心人士可以透過這個方式直接覆寫資料表裡某個欄位的值而取得特別權限或修改原本不應該被修改的欄位資料。
Rails 4 之後提供了一種稱之 Strong Parameters 的做法,讓你可以對這包 params 進行「清洗」或「過濾」,寫法如下:
class CandidatesController < ApplicationController
# .. [略] ..
private
def candidate_params
params.require(:candidate).permit(:name, :age, :party, :politics)
end
end
方法名稱可自定,這裡我使用了 candidate_params
這個名字。因為這個方法沒有需要給外部存取,所以通常會放在 private
區塊。裡面的 permit
方法就是說「我只允許 name
、age
, party
以及 politics
這四個參數通過,其它的來我會無視」。因為 params[:candidates]
的內容現在只能通過你有「放行」的欄位,所以就算是被「清洗」過了。
所以,接下來把原本這行:
@candidate = Candidate.new(params[:candidate])
改成:
@candidate = Candidate.new(candidate_params)
因為這個 candidate_params
回傳的資料應該是「乾淨」的,所以 Rails 就可以讓你把整包資料寫進去了。試著填寫一些資料:
按下按鈕後應該就可以新增資料了:
想一想:為什麼新增資料失敗的時候是用 render 而不是用 redirect_to?
剛剛在新增資料的時候,如果新增資料成功,會轉址(redirect_to)到候選人列表頁;如果失敗,則是會執行這行:
render :new
為什麼不是 redirect_to new_candidate_path
轉到前一頁就好了呢?
因為當使用 redirect 方式之後,等於是再次進到 /candidates/new
網址,也就是再執行了一次 new
這個 action,所有剛剛填的資料都會隨著消失;但 render :new
並不是「轉址」,而是「我還是執行 create
這個 action,只是顯示的時候借用 new
的 view
來用」而已,不是重新執行 new 這個 action 喔,很多新手在一開始接觸 Rails 時以為 render :new
是執行 new 這個 action,這點要特別注意。
想想看如果你在填寫報稅系統,要繳稅已經不太開心了,填了一堆資料之後結果卻因為某個欄位填錯結果轉回來叫你全部欄位重填,你應該會翻桌吧。
另外,你有發現在 create
這個方法裡,剛好用了 @candidate
這個實體變數嗎:
def create
@candidate = Candidate.new(params[:candidate])
if @candidate.save
redirect_to candidates_path, notice: "新增候選人成功!"
else
render :new
end
end
正常來說,如果不需要用到實體變數,建議是只要使用區域變數就好,但因為在處理失敗狀況的 render :new
,剛好在 new 的 view 有用到 @candidate
這個實體變數,所以在 create
方法裡才使用了 @candidate
實體變數,如果不考慮資料寫入失敗的狀況,是不需要使用實體變數的。在 new
跟 create
方法的實體變數都剛好叫做 @candidate
這個名字並不算是巧合,而是刻意使用一樣的命名,讓程式碼可以變得簡短、易讀。
第 07 步 -「編輯候選人資料」功能 Part 1
完成「新增」功能後,接下來是編輯功能,先在列表頁(index.html.erb)把「編輯」的連結加上去,「刪除」跟「投票」的連結也順便先加一下:
<h1>候選人列表</h1>
<%= link_to "新增候選人", new_candidate_path %>
<table>
<thead>
<tr>
<td>投票</td>
<td>候選人姓名</td>
<td>政黨</td>
<td>政見</td>
<td>得票數</td>
<td>處理</td>
</tr>
</thead>
<tbody>
<% @candidates.each do |candidate| %>
<tr>
<td><%= link_to "投給這位", "#" %></td>
<td><%= candidate.name %>(年齡:<%= candidate.age %> 歲)</td>
<td><%= candidate.party %></td>
<td><%= candidate.politics %></td>
<td><%= candidate.votes %></td>
<td>
<%= link_to "編輯", edit_candidate_path(candidate) %>
<%= link_to "刪除", candidate_path(candidate), method: "delete", data: { confirm: "確認刪除" } %>
</td>
</tr>
<% end %>
</tbody>
</table>
這邊沒有太複雜的程式碼,只用了 link_to
方法加了三個連結。幾件事情說明一下:
- 如果不知道那個
_path
怎麼寫,請到終端機執行rails routes
查閱prefix
欄位。 - 因為投票的路徑還沒寫,所以我先把連結設定成
#
。 link_to
的 HTTP 動詞要用對,該用POST
或DELETE
但卻忘了加的話,會造成找不到路徑的錯誤訊息。- 在投票跟刪除連結後面另外加的
data: { confirm: "..." }
參數,會在做出來的連結中加上data-confirm="..."
屬性,而 Rails 在處理這樣的連結屬性時,會跳出一個確認對話框,待使用者按下確認後才會繼續執行,避免不小心按到就直接投票或刪除了。
現在的畫面應該會長得像這樣:
第 08 步 -「編輯候選人資料」功能 Part 2
既然要「編輯」某一筆資料,首先要先在 Controller 裡把那筆資料抓出來:
class CandidatesController < ApplicationController
# .. [略] ..
def edit
@candidate = Candidate.find_by(id: params[:id])
end
# .. [略] ..
end
edit
方法的位置不一定要在 new
或 create
的前面或後面,只要找個看得順眼的地方而且不是在 private
區塊就行了。
使用 Model 的 find_by
方法,把 id
是 params[:id]
的資料抓出來,並把找到的結果存成實體變數 @candidate
。
這個 params[:id]
是什麼?先讓我們執行 rails routes
來看一下:
$ bin/rails routes
Prefix Verb URI Pattern Controller#Action
.. [略]..
new_candidate GET /candidates/new(.:format) candidates#new
edit_candidate GET /candidates/:id/edit(.:format) candidates#edit
candidate GET /candidates/:id(.:format) candidates#show
PATCH /candidates/:id(.:format) candidates#update
PUT /candidates/:id(.:format) candidates#update
DELETE /candidates/:id(.:format) candidates#destroy
在候選人列表頁,當你點下編輯之後,它的網址會變成像是 /candidates/1/edit
,跟 Route 比對之後就可以發現,中間的那個數字 1
就是在 Route 路徑裡的 :id
,它會被捕捉在 params
裡,使用 params[:id]
就可以調出來使用。
注意:透過
params
取得的所有資料型態都是字串,包括看起來像是數字的params[:id]
也是字串,如果是要直接拿來做數學運算的話,請記得先使用to_i
或to_f
方法轉換型態。
接著,編輯 app/views/candidates/edit.html.erb
頁面:
<h1>編輯候選人</h1>
<%= form_for(@candidate) do |f| %>
<%= f.label :name, "姓名" %>
<%= f.text_field :name %> <br />
<%= f.label :age, "年齡" %>
<%= f.text_field :age %> <br />
<%= f.label :party, "政黨" %>
<%= f.text_field :party %> <br />
<%= f.label :politics, "政見" %>
<%= f.text_area :politics %> <br />
<%= f.submit %>
<% end %>
<br />
<%= link_to '回候選人列表', candidates_path %>
咦?等等!各位有發現這段程式碼的內容怎麼跟新增頁面的程式碼有九成像?其實這就是 form_for
方法神奇的地方。因為 form_for
發現傳進來的那顆 @candidate
物件是舊的(就是從資料庫裡調出來的),它會認定你是準備要「編輯」,所以不只 <form>
的 Action 網址會幫你依照慣例設定好,連值也會自動幫你帶進表單裡。
這時候的畫面長這樣:
但這個程式碼跟新增的實在是太像了,所以我們可以把重複的地方抽出來,存在另一個檔案。請手動新增一個叫做 _form.html.erb
的檔案,放在 app/views/candidates/
裡,內容如下:
<%= form_for(candidate) do |f| %>
<%= f.label :name, "姓名" %>
<%= f.text_field :name %> <br />
<%= f.label :age, "年齡" %>
<%= f.text_field :age %> <br />
<%= f.label :party, "政黨" %>
<%= f.text_field :party %> <br />
<%= f.label :politics, "政見" %>
<%= f.text_area :politics %> <br />
<%= f.submit %>
<% end %>
注意在抽出來變成的內容中,把實體變數(也就是 @
開頭的變數)換成區域變數,原因待會會說明。原本「新增」的頁面 app/views/candidates/new.html.erb
的內容可改成這樣:
<h1>新增候選人</h1>
<%= render "form", candidate: @candidate %>
<br />
<%= link_to '回候選人列表', candidates_path %>
「編輯」的頁面 app/views/candidates/edit.html.erb
的內容也可改成這樣:
<h1>編輯候選人</h1>
<%= render "form", candidate: @candidate %>
<br />
<%= link_to '回候選人列表', candidates_path %>
現在「新增」跟「編輯」這兩個頁面都變得短短的二、三行就搞定,把共同的內容都放到 _form
裡面了。這個技巧在 Rails 稱之局部渲染(Partial Render),通常會用來整理重複的程式碼。檔名不一定要叫 _form
,你也可以取做 _abcdefg
,但要用的時候就要改寫成 <%= render "abcdefg" %>
。
注意:這個 Partial Render 的檔案名稱必須要是底線開頭,不然會發生找不到的檔案錯誤訊息。
想一想:為什麼要把局部渲染的實體變數抽掉?
在剛才使用局部渲染手法整理程式碼的時候,抽出程式碼到 partial file 的時候,大可使用剪下、貼上的手法,像這樣:
<%= form_for(@candidate) do |f| %>
<%= f.label :name, "姓名" %>
<%= f.text_field :name %> <br />
...[略]...
<% end %>
然後在使用的時候只要這樣:
<%= render "form" %>
讓 _form.html.erb
直接裡取用空中的實體變數 @candidate
,使用起來簡單又方便!但為什麼不建議這麼做呢?
因為使用這樣的寫法,_form.html.erb
就會變成依賴這個命名為 @candidate
的實體變數才能正常運作。這不算是個好設計,因為這樣一來在產生這個實體變數的時候,就只能叫做 @candidate
這個名字了。
較建議的做法,是讓這個檔案設計成「被動」或「被餵食」,而達到「解耦」(decoupling)的效果,像是這樣:
<%= form_for(candidate) do |f| %>
<%= f.label :name, "姓名" %>
<%= f.text_field :name %> <br />
...[略]...
<%= f.submit %>
<% end %>
簡單的說,就是 partial file 裡不要放實體變數,僅使用區域變數。以這個例子來說,_form.html.erb
這個檔案只期待有一個叫做 candidate
的區域變數,在使用它的時候,可透過 render
方法的時候傳額外的參數傳給它:
<%= render "form", candidate: @candidate %>
萬一在別的地方也要使用這個 partial file,但實體變數名稱叫做 @qualified_candidate
:
<%= render "form", candidate: @qualified_candidate %>
_form.html.erb
只要外面有傳一個 candidate
變數給它,它就可以正常運作了。在第 15 章有關於 View 跟 Layout 的介紹,也會針對這個主題再補充說明。
第 09 步 -「編輯候選人資料」功能 Part 3
根據 Route 的路徑對照表,當對 /candidates/:id
網址以 PUT
或 PATCH
方式傳送時,會觸發 CandidatesController 上的 update
方法,所以接下來我們把這個功能給補上去:
class CandidatesController < ApplicationController
# ..[略]..
def update
@candidate = Candidate.find_by(id: params[:id])
if @candidate.update(candidate_params)
# 成功
redirect_to candidates_path, notice: "資料更新成功!"
else
# 失敗
render :edit
end
end
# ..[略]..
end
update
方法寫起來其實也跟 new
有點像,差別在於這邊是使用 update
方法(或使用 update_attributes
方法也可)更新資料。同樣的,為了安全考量,如果 update
方法是直接丟沒有清洗過的 params[:candidate]
給它,也一樣會發生錯誤訊息。若編輯更新成功,將會轉往候選人列表頁面,若失敗則重新 render 編輯頁面。
到這裡,編輯功能應該就完成了!
第 10 步 -「刪除候選人資料」功能
跟「新增」或「編輯」功能比起來,刪除功能算是相對簡單的,只要把資料抓出來就可以直接刪除了。根據 Route 的路徑,對 /candidates/:id
網址以 DELETE
發送資料時,會觸發 CandidatesController 的 destroy
方法,所以就讓我們把 destroy
方法加上去:
class CandidatesController < ApplicationController
# .. [略] ..
def destroy
@candidate = Candidate.find_by(id: params[:id])
@candidate.destroy if @candidate
redirect_to candidates_path, notice: "候選人資料已刪除!"
end
# .. [略] ..
end
這樣一樣使用 Model 的 find_by
方法,把要刪除的資料抓出來,然後呼叫那個物件的 destroy
方法,這筆資料就會刪掉了。
小結
到這裡,我們已經可以不使用內建的 Scaffold 產生器而完成候選人資料的新增、修改、刪除功能了。不過目前的程式碼寫得有點醜,而且不少地方是重複的,下一個章節將介紹怎麼幫它加上投票功能以及整理重複的程式碼。
以上實作完整程式碼可在 https://github.com/kaochenlong/my_candidates 取得。
Comments