候選人票選系統純手工打造
.基本新增修改刪除介紹
.使用vscode編輯
.參考資料: 為你自己學Ruby On Rails
00 開始之前
step 1. 使用指定Rails版本生成專案:
rails _版本_ new 專案名
% rails _6.1.5_ new hello_rails
step 2. 進到該資料夾 cd hello_rails
git版控初始化
git init
step 3. 第一次commit
git add .
git commit -m"init commit"
step 4. 確定環境正常運作
rails s
進到localhost:3000確認畫面
01處理Route,新增(建立)路徑
step 1. 找到Route檔 confing -> routes.rb (或是使用ctrl+p搜尋)
step 2. 做出候選人相關資源/路徑 在routes.rb檔案裡輸入
|
|
rails routes
可查看路徑對照表
可看到做出的八條路徑,對應到七個action
candidates#index
candidates#create
candidates#new
candidates#edit
candidates#show
candidates#update
candidates#update
candidates#destroy
若只想做出特定路徑,如index跟show,示範如下
|
|
step 3.新增controllers
app -> controllers 按右鍵新增檔案
candidates_controller.rb
接著,在檔案裡面輸入
|
|
step 4. 新增view
app -> views 按右鍵新增資料夾
candidates
在candidates裡再新增檔案
index.html.erb
輸入
|
|
這時,就可以在
localhost:3000/candidates
看到剛剛輸入的Hi了
step3-step4手工打造的部分,可使用指令
% rails g controller candidates
02 新增Model
step 1.使用指令新增model
要先想一下Candidate的Model要有哪些欄位及其對應的資料型態
Model不等於資料庫/資料表,是一個抽象層的概念
這個過程如果要純手工,會涉及到需手動建立migration檔來描述這個資料表要長什麼樣子,需要寫一些語法,對現階段的我們來說會有點吃力,建議直接使用指令
% rails g model Candidate name:string party:string age:integer politics:text votes:integer
如果是文字型態(string),可省略不寫
% rails g model Candidate name party age:integer politics:text votes:integer
這個指令會幫你做兩件事
- 建立candidate這個model
- 會根據你給它的欄位,建位一個migration(主要目的)
慣例:如果model叫Candidate(大寫單數),資料表migrate中的表格table就會是candidates(小寫複數)
step 2.描述檔具現化
% rails db:migrate
會在 db 這個資料夾建立檔案 檔案名為:
development.sqlite3
在rails預設使用的資料庫就是sqlite,它是一種檔案型的資料庫,效能不好,但簡單易用,以練習來說還算堪用,在我們這次開發過程中所有資料都會寫到這裡。
在config/database.yml裡的adapter可以確認本次專案所使用的資料庫系統
在不同的環境(開發、測試),會存放在不同的資料庫
例如
開發:
database:db/development.sqlite3
測試:
database:db/test.sqlite3
03 新增候選人表單
step 1. 確認表單路徑
在
% rails routes
找到
candidates/new
step 2. 寫入連結
回到00章節中 step4 裡在candidates建立的index,在裡面寫入
|
|
就可以在
localhost:3000/candidates
頁面看到我們設定的超連結了。但這時點下去這個超連結,應該會出現在錯誤訊息,因為我們還沒有做出相對應的action給它。
step 3.定義 new action
回到
candidate_controller.rb
定義 new action
|
|
step 4. 做出 new 的view
在views -> candidates 新增檔案
new.html.erb
輸入
|
|
就可以在localhost:1313/candidates/new
看到這行新增履歷的文字了
03-1 手刻建立表單
step 1. 建立 form 表單,使用POST方法
在 new.html.erb
檔裡寫入
|
|
這邊要稍微記一下(或是可以參考路徑對照表),在我們從candidates/new
這邊,用POST方法往candidates送,那接著就會要找create這個action
candidate#create
step 2.定義create action
回到
candidate_controller.rb
定義 create action
|
|
step 3. 認識rails預設的保護機制
為避免票務或其他相關設計的灌水問題,在使用form表單要往某個地方送的時候,rails會要求要有 authenticiy token。我們可以用以下的 ruby 方法<%= form_authenticity_token %>
讓每次載入頁面時,會生出一段authenticity token。按下送出時這段token就會跟著表單一起送到 action。目的是要透過由我們發出去的 authenticity token 來確認用戶是從我們網站進來的,進而達到避免有心人士使用自己寫的程式來不停送出(票數)灌水。
|
|
03-2 使用form_for小幫手
在rails裡,有個叫form helper的小幫手,使用它來幫助我們建立表單。就不用像03-1過程這麼繁瑣。
step 1. 使用form_for
form for 是為了某個model建立表單, 語法如下form_for(model)
,套用在我們這次的實作,因為Candidate
是一個class,所以我們在後面加上.new
,讓它變成一個model。並把它定義在candidates_controller.rb
的new
裡。並給它一個實體變數(@),view才能拿的到。
(之所以要把model定義在controller裡,是因為在 MVC 結構裡,view 的角色就是單純把東西印出來,不要做產生物件或邏輯運算之類的事,屬於被動角色)
|
|
回到candidates/new
,把定義好的實體變數接在form_for裡
<%= form_for(@candidate) %>
form_for 發現後面接的是全新的model的時候,會幫你長出相對應的路徑、方法包含token全部寫完。
step 2. 搭配 ruby 的 程式碼區塊(Block)
搭配 ruby的程式碼區塊(Block)do end
加上小幫手的.text_field
方法來產生欄位,及.label
方法來做出標籤
|
|
03-3 create action
step 1. 得到parameters
params 是一個方法會回傳 ActionController::Parameters 物件,在實務上會像一個 hash。所以我們可以透過params來取得parameters。
在 03-2 把表單建立好,按下送出之後,在 log 中可以發現一包參數(parameters),裡面包含token、欄位所填的資料
,我們就可以透過params這個hash,使用candidate這個key來取得相對應的一包hash(value)
|
|
丟給Candidate.new
這個model。接著使用(@)實體變數建立物件,叫這個物件存檔(save)。如果成功,就把頁面導向候選人列表頁。 如果失敗,使用 render 這個方法,借 new 的頁面重新渲染。render :new
|
|
補充說明 1:hash是什麼?
hash是由key、value所組成的資料,設計者只要根據Key值就可以取得相對應的資料。
如何建立hash?
1.使用hash類別,new一個給他。
user = Hash.new
2.使用大括號
user = { name: ‘Judy’, age:8 }
補充說明 2:製造巧合
在 new 及 create 取了一樣的實體變數名字,讓render :new
可以順利在空中抓取資料並透過form_for
讓值擺放在相對應的欄位。
def new
@candidate = Candidate.new
end
def create
@candidate = Candidate.new(candidate_params)
end
step 2. 清洗params
當我們試圖要把整包hash的資料透過 model 寫進資料庫的時候,model會發現這包網路上抓下的東西還沒清洗(過濾檢查)過(使用者可以很輕易的在頁面上編輯加欄位)。預設會擋下來。
使用 require 這個方法,抓取candidate並使用permit只允許部分欄位過來。
|
|
接著,設定一個變數名稱給它,或是知道我們後面會很常再使用它,可以直接定義方法。再把它放進Candidate.new
這個model。
第一個方式如下:
|
|
第二個方式,把它單獨定義一個方法,讓它可以被重複使用,因為不需被外部存取,可以加入 private 註記,變成私有方法。是一個比較好的作法。
|
|
step 3. 確認存取的資料
在rails console
或 rails c
輸入
Candidate.all
就可以印出目前Candidate這個表格裡的所有候選人
step 4. 使用者提示 flash
flash 是快閃訊息的意思,只要印在畫面一次之後,就會消失。
flash 本質上就是一個hash。key的慣例上會使用notice
,後面再接上要給的訊息。寫的方式如下:
|
|
接著,就在要印出這個flash的html頁面寫入
|
|
03-4 加入驗證
在 app -> models 裡的 candidate.rb
檔,根據我們的驗證條件寫入 validates
|
|
03-5 撈出候選人列表
我們已經順利把候選人寫入資料庫了,現在要把資料撈出來。在candidates_controller.rb
這裡透過 Candidate 這個 model 的類別方法 all Candidate.all
|
|
並且在index.html.erb
這個檔案裡用table,搭配使用ruby的迴圈each
把候選人資料一筆一筆印出來
03-6 link_to
View-helper小幫手link_to
|
|
第二種寫法,使用路徑 Prefix 提供的名稱加上 _path
|
|
第二種寫法的優點
- 拼錯就會馬上噴錯
- 之後更改路徑名稱方便
所以盡量以第二種寫法為主。
03-7 show action
step 1. 重覆之前在controller定義action的方式定義show action。注意不要放在private底下。
|
|
step 2. 做出view show.html.erb
step 3. 透過params拿id欄位回來用
透過params拿id欄位回來,再透過modle的find_by方法找某候選人的資料
|
|
step 4. 在show.html.erb
做列表,把find_by 找到的資料印出來,會根據不同的id而有不同的結果。
step 5. 加上 if 判斷 如果候選人有資料,就印出來,反之,印出no record
|
|
補充說明
<%= %> 與 <% %>
兩者的差別在於需不需要於畫面輸出,有加=
的會印出來。
03-8 沒有通過驗證的錯誤訊息
step 1.透過any?
來詢問有沒有任何錯誤訊息
.errors.any?
這時,對照03-3的save,存檔過程中要是沒有通過驗證,就可以在
.errors.any?
得到true的結果
再使用full_messages
來得到錯誤訊息
.errors.full_messages
一樣搭配.each
的方法來逐個印出資訊
|
|
補充說明 可以透過
.method
的方法來確認有什麼method可以使用
step2. 修正版面
因為驗證沒有過而render :new 回來後,版面會因為被多了一層div(field_with_errors)包裏而跑掉,我們要怎麼處理呢?
來到 app -> assets -> stylesheets 資料夾裡按右鍵開一個檔案candidate.scss
。這個資料夾裡的所有css檔案可以透過同個資料夾的application.css
(打包描述檔)裡的這個描述
*= require_tree .
打包回來。
接著,就可以在candidate.scss
編輯想要的效果。
|
|
04 修改(edit)
一樣使用前面提到的link_to
來寫。
step 1. 確認路徑
/candidates/:id/edit
step 2. 確認Prefix
edit_candidate
step 3. 在index.html.erb
寫入
|
|
補充說明
若Prefix的欄位是空白的,則對應的是前一個欄位
04-1 edit action
step 1. 重覆之前在controller定義action的方式定義edit action。注意不要放在private底下。並且一樣透過params拿id欄位回來,再透過modle的find_by方法找某號候選人的資料
|
|
step 2. 做出view edit.html.erb
step 3. 做一個表單
(可用new.html.erb的內容來套用)
step 4. PATCH / UPDATE
接下來在瀏覽器按下update
後,可以在log裡看到form_for幫我們產出的其中一個input,有patch這個方法。
|
|
這是因為目前瀏覽器還沒有支援到那麼多的方法(動詞),所以rails用這個方式"假裝"patch(實際上是post)
由路徑對照表可以看到,如果是用PATCH的方法對/cnadidates/:id
這個路徑去送的話,會對應到candidates#update
這個方法。
補充說明 1.
rails會根據那個modle是不是全新的來判斷(猜測)form.submit
是要使用create還是update
全新的物件 -> create
從資料庫撈出來的 -> update
補充說明 2.
(1) 用GET的方法對/cnadidates/:id
這個路徑去送的話,會找到candidates#show
這個方法
(2) 用PUT的方法對/cnadidates/:id
這個路徑去送的話,會找到candidates#update
這個方法
(3) 用DELETE的方法對/cnadidates/:id
這個路徑去送的話,會找到candidates#destroy
這個方法
04-2 update action
step 1. 重覆之前在controller定義action的方式定義edit action。注意不要放在private底下。並且一樣透過params拿id欄位回來,再透過modle的find_by方法找某號候選人的資料
|
|
step 2. 類似 create action 的作法,並且失敗的話,借edit的頁面來渲染
|
|
05 刪除
step 1. 確認路徑
/candidates/:id
step 2. 確認Prefix
candidate
(沒寫的話的,為同上)
step 3. 在index.html.erb
寫入
|
|
step 4. 做出跟update的區別
到目前為止,因為跟update一樣路徑都是在/candidates/:id
所以要在 link_to 裡加幾個參數,讓它不會往show送
|
|
在檢視原始碼的時候,就會發現多出data-mathod="delete"
如此,在頁面上按下delete
的時候,就會對該路徑使用delete這個動詞,接著往/cnadidates/:id
這個路徑去送,會找到candidates#destroy
這個方法
05-1 destroy action
step 1. 重覆之前在controller定義action的方式定義edit action。注意不要放在private底下。並且一樣透過params拿id欄位回來,再透過modle的find_by方法找某號候選人的資料
|
|
step 2. 防呆機制
在index.html.erb
裡的link_to加上確認data: {confirm:""}
|
|
如此,便可以在刪除資料的時候,跳出確認視窗
06 錯誤訊息
錯誤訊息的解答通常都在訊息裡
錯誤訊息:missing a template 代表缺少MVC裡的V(view),需要在view裡建相對應的 html 給它
錯誤訊息:Migrations are pending 代表還有一個migrations還沒處理,執行rails db:migrate就可以解決
錯誤訊息:UnKnown action 代表缺少某個action,需要在 controller 裡定義
錯誤訊息:Routing Error. No route matches 找不到路徑(有可能是還沒建或是路徑打錯字)
錯誤訊息:InvalidAuthenticity Token 無有效的驗證
錯誤訊息:ForbiddenAttributesError 還沒清洗params(還不是白名單)
rails設計哲學之一就是慣例優於設定