打造Rails App(四) — To do list
透過遵循Alpha camp的課程內容,一步一步的把第一個Rails App-相簿做出來後,針對整個Ruby on Rails的App開發有了初步的架構跟觀念了,當然這樣是不夠的,所以第一個打造Rails App的初階專案來囉,就是打造一個Rails app — To do list,為了加深印象跟重新再複習,所以特在Medium上將步驟拆解並記錄下來。
User Stories:
- 使用者可以建立 to do 項目,各個 to do 項目要能儲存以下資訊:名稱 (name)、必須完成時間 (due date)、其他說明 (note)
- 使用者可以看到一張 to do 清單,清單上呈現了 to do 的資訊
- 使用者能在 to do清單上很方便地選擇要刪除、修改、或去看詳細的內容
- 如果 due date 已經過期,就不能再刪除 to do 了
- 最後,請使用 Bootstrap 美化這個 To do list
下圖是第一版完成的樣式,
接著就開始拆解完成上圖的各個步驟囉!
1. 建立Rails App專案:to_do_list
1–1. 打開terminal輸入建立Rails App專案to_do_list的指令,如下
$ rails new to_do_list
1–2. 輸入指令進到to_do_list目錄下,進行後續動作
$ cd to_do_list
而關於目錄下各個資料夾所負責的任務可以參考:打造Rails App(二) — Route + MVC目錄結構。
2. 建立Model
專案目錄產生後,接著要開始建立model然後遷移資料庫,這裡我們先來建立model吧!
2–1. 進到to_do_list目錄下後,在terminal輸入指令,建立一個叫做task的 model,
$ rails generate model task
2–2. task model建立完成後,在db/migrate目錄下產生/新增 task model 的資料庫遷移(migrate)記錄20171018014822_create_tasks.rb檔案
2–3. 在app/models目錄下也產生/新增了task.rb這個Task model檔案
至於資料庫遷移紀錄檔及task model檔案內有什麼內容這邊就不多加說明,可以參照:打造Rails App(三) — Ruby on Rails Active Record。
3. 建立資料表(Table)在資料中
要完整建立Task model的話,Task model 的一舉一動還需連結著資料庫裡一張叫 tasks 的資料表 (table),並透過 Active Record 提供的許多方法,同時操作 Task model、也同時操作 tasks table。接著讓我們來建立tasks table吧,
3–1. 在db/migrate目錄下的資料庫遷移(migrate)記錄20171018014822_create_tasks.rb檔案中,編輯資料結構
3–2. 在terminal中輸入資料遷移指令產程資料表(Table),
$ rails db:migrate
然後tasks table就建立完成了!
註:Rails慣例-命名
1. Model命名為單數且開頭為大寫;所以在這專案model名稱為Task
2. Table預設為負數且以小寫及底線分隔命名;所以在這專案table名稱為tasks
4. Route設定
Rails中的Route會根據接受到的HTTP Request Method及URI比對Route中對照表的資料,是整個Rails App的第一關!
4–1. 打開在config/routes.rb,使用resources方法自動產生8個路徑及7個action。resources方法程式碼如下,
resources :task
4–2. 在terminal中查看Rails routes,執行下列指令進行查看設定,
$ rails routes
會發現在routes.rb未使用resources方法前,查詢routes的結果會是未定義任何routes;在routes.rb中輸入resources :task使用resources方法後,在查詢一次routes的結果會是顯示完整的 CRUD 路徑(8個路徑及7個action),然後routes就設定好了!
5. 建立控制器(controller)
Rails中的Route會根據接受到的HTTP Request Method及URI比對Route中對照表的資料後,就決定由controller中哪個Action繼續執行後續動作。route在上一個步驟設定好了,有了路徑也知道往哪去,這個步驟就開始建立要去的地方也就是controller!
5–1. 建立tasks controller,在terminal中執行下列指令,
$ rails generate controller tasks
除了新增 app/controllers/目錄下的tasks_controller.rb 及 app/views/tasks 目錄之外,也產生了相關的測試檔、JavaScript(CoffeeScript)、CSS(SCSS)檔案。
想了解app/controllers/tasks_controller.rb的初始內容有什麼含義可以參照:打造Rails App(三) — Ruby on Rails Active Record
6. 在controller中建立第一個Action
Controller建立好了,但是裡面沒有宣告任何action要使用的方法(method),讓我們著手建立第一個action!
6–1. 在app/controllers/tasks_controller.rb中宣告index action要使用的方法(Method)
在route設定中,若要使用當時產生的7個action,則均須在tasks_controller.rb中宣告各個action欲使用的方法(method)。
7. 建立view替action controller的資料樣板化
Action Controller將Model回傳的資料處理完畢後交給View樣板化。
7–1. 在app/views/tasks目錄下,新建立index.html.erb檔案
7–2. 打開index.html.erb並著手編輯index頁面
7–3. 此時在terminal輸入指令連線至server並在瀏覽器開啟專案頁面(http://localhost:3000/)會看到下圖,
$ rails server
會發現怎麼沒有顯示出先前在index.html.erb中所編輯的頁面!別急,因為我們沒有幫Rails App設定根目錄!
7–4. 在routes.rb中輸入下方程式碼設定根目錄,
root "tasks#index"
7–5 執行rails console,並建立一筆資料在資料表中,
7–6. 專案有了根目錄,也有了一筆資料,讓我們再次連線到專案頁面(http://localhost:3000/)會看到下圖!
這個步驟滿足了user story:
使用者可以看到一張 to do 清單,清單上呈現了 to do 的資訊
8. 建立CRUD -Create的action method 跟 view頁面
CRUD 是 Create(新增)、Read(讀取)、Update(更新) 跟 Delete(刪除),開發 CRUD 應用程式是Rails的強項。上一步驟已經完成index action跟view頁面了,而下面是此次專案所有action跟view,
在這個步驟我們將建立CRUD- Create及view頁面。
8–1. 在app/controllers/tasks_controller.rb中宣告new action要使用的方法(Method)
8–2. 在app/views/tasks目錄下,新建立new.html.erb檔案並編輯new頁面
8–3. 連線到new頁面(http://localhost:3000/tasks/new)所呈現出來的view頁面,如下
8–4. 在app/controllers/tasks_controller.rb中宣告create action要使用的方法(Method)及在primary下宣告params這個method,以取得new頁面表單傳過來的欄位資料
8–5. 連線至新增頁面(http://localhost:3000/tasks/new),將欲新增的task內容填入task表單中,並按下“create”建立task資料
然後就會回到index頁面且該筆資料也會出現在index頁面中,如下,
這個步驟滿足了user story需求:
使用者可以建立 to do 項目,各個 to do 項目要能儲存以下資訊:名稱 (name)、必須完成時間 (due date)、其他說明 (note)
9. 建立CRUD -Read的action method 跟 view頁面
9–1. 在app/controllers/tasks_controller.rb中宣告show action要使用的方法(Method)
9–2. 在app/views/tasks目錄下,新建立show.html.erb檔案並編輯show頁面
9–3. 連線至第一個task(http://localhost:3000/tasks/1),show頁面如下
這個步驟滿足user story:
使用者能在 to do清單上很方便地選擇看詳細的內容
10. 建立CRUD -Update的action method 跟view頁面
10–1. 在app/controllers/tasks_controller.rb中宣告edit action & update action要使用的方法(Method)
10–2. 在app/views/tasks目錄下,新建立edit.html.erb檔案並編輯edit頁面
10–3. 連線至第一筆task的edit頁面(http://localhost:3000/tasks/1/edit),將欲更新的task內容填入task表單中,並按下“update”更新task資料,如下圖,
更新完後,頁面會指向show頁面顯示更新後的task內容,如下圖,
這個步驟滿足user story:
使用者能在 to do清單上很方便地選擇要修改的內容
11. 建立CRUD -Destroy的action method
11–1. 在app/controllers/tasks_controller.rb中宣告destroy action要使用的方法(Method)
11–2. 在index.html.erb中編輯index頁面時,宣告了使用delete methode 前執行confirm的動作
至此,我們已經完成CRUD的建立了!
這個步驟滿足了user story:
使用者能在 to do清單上很方便地選擇要刪除
12. 執行Destroy時,判定時間是否overdue
12–1. 在tasks_controller.rb的destroy method中使用if…else
進行時間是否overdue的判定。如果現在時間在task due date之前,則成功刪除且頁面指向index頁面;反之,如果現在時間在task due date之後,因為overdue則無法刪除且頁面指向index頁面。
12–2. 提示訊息(Flash Message):在application.html.erb中編輯顯示Rails的flash hash,讓在tasks_controller.rb的destroy method中宣告的notice訊息得以顯示在頁面中。
<p><%= flash[:notice] %></p>
通常會用 Flash 來顯示錯誤、提示訊息等,通常會在應用程式的版型檔案
app/views/layout/application.html.erb
,加入提示訊息所需的 View
12–3. 接著就來測試destroy 判別overdue的測試(測試時間:2017–10–19)
這個步驟滿足了user story:
如果 due date 已經過期,就不能再刪除 to do 了
13. 重構程式碼
在這個步驟之前,我們在建構Rails app的過程中重複寫了許多相同的程式碼,但是當重複的程式碼越多在維護上相對就更不容易,也會影響應用程式的品質。所以我們的目標是若之後應用程式需要任何的變動,我們只需要在同一個地方維護程式碼即可,且不會遺漏任何部分,以確保應用程式的品質。所以我們以Don’t Repeat Yourself(DRY) in Ruby on Rails的理念進行程式碼的重構。
13–1. 在primary method下宣告set_task這個method取代在app/controllers/tasks_controller.rb中show、edit、update 和 destroy method中均重複宣告的實例變數,如下
def set_task
@task = Task.find(params[:id]) #重複宣告的實例變數
end
13–2. 宣告set_task method後,使用過濾器(filter) before action(也是回呼方法 (Callback Method) 的一種),要求Rails在執行任何或指定action前先執行set_task方法。在這邊過濾器在Rails執行show、edit、update 和 destroy method前會先執行set_task method。
有過濾器(filter) before action後,就可將各method中重複的@task = Task.find(params[:id])
刪除。
13–3. 接著我們著手進行view的程式碼重構,首先在app/views/tasks目錄下新增局部頁面(Partial Template)檔案 ”_form.html.erb”
13–4. 將”new.html.erb” 及 “edit.html.erb” 檔案中重複的程式碼移至“_form.html.erb”局部頁面檔案中便於之後程式碼維護。
13–5. 在”new.html.erb” 及 “edit.html.erb” 檔案中輸入下列程式碼,告訴 view頁面來輸出名稱叫做 ”form” 的局部頁面。
<%= render :partial => "form" %>
以上5個步驟就完成了tasks_controller.rb 及 view頁面的程式碼重構,達到DRY的目標。
14. 表單輸入資料驗證機制的建立
我們都會有失誤,如果今天在建立新task或更新task內容的時候不小心按到create或update的按鈕,可能會產生一筆不完整的資料,甚至是一筆完全沒有資料的task!為了避免失誤發生,我們新增ActiveRecord 的 Validation 驗證功能,透過 Rails 提供的方法,讓表單中的所有區塊都成為必填項目。
14–1. 在app/models/task.rb中使用下列指令使表單中所有區塊都成為必填項目。
validates_presence_of :name, :date, :note
14–2. 在局部頁面編輯顯示驗證錯誤訊息在頁面給user看
<% if @task.errors.present? %>
<ol>
<% @task.errors.each do |error, message| %>
<li>WARNING: <%= "#{error.capitalize} #{message}" %></li>
<% end %>
</ol>
<% end %>
這樣就完成了簡單的料驗證!
15. 使用 Bootstrap 美化這個 To do list
先呈現出用Bootstrap簡單美化後的頁面樣貌