---
# System prepended metadata

title: 0401 TDD 延伸及網站建置延伸
tags: [Ruby / Rails]

---

# 0401 TDD 延伸及網站建置延伸
###### tags: `Ruby / Rails`

## TDD 練習：YouBike
[專案 GitHub 連結](https://github.com/5xTraining/tdd-youbike)
    
* 沒有頭緒是正常的 XDDDDD
* 但還是希望可以先寫再對答案，才有意義
* pending 只是作為提醒，哪裡的測試還沒寫
* 在 Ruby 中如果找不到 Hash 中的 Key 會得到 `nil`，不會有錯誤。
* 在 RSpec 裡主要是測試 **行為** -> BDD （Behaviour-Driven Development）
    *  BDD，專注在物件行為上進行測試撰寫；關注行為，非細節
* 依照需求去創造更多方法或表格 -> 程式是活的，看寫的人怎麼想，有無限可能
* 誰收錢，需要第三個類別物件，例如購物車的腳色
    * DB 正規化，寫一寫不知道資料放哪裡時，要多加資料表
    * rental: Rental.new(user)
    * 行為合理，程式碼才好寫，合理再寫細節
    * 有用到再加功能，TDD
    * 租/還行為by Renal

### 命名慣例
#### 在方法命名後面加 `?` 
例：`return?`
1. 通常為判斷式（回傳布林值 Boolean）
2. 在大型專案中加 `?` ，可前往手冊查閱實際意義
3. 在 RSpec 或某些框架中會直接附帶功能建立判斷式
* 方法內容要自行定義，但就是增加語意用
```ruby=
(rspec附帶的功能)
expect(user.member?).to be true == expect(user).to be_member
expect(user.member?).to be false == expect(user).not_to be_member
```
[官網 to_be 解釋](https://relishapp.com/rspec/rspec-expectations/docs/built-in-matchers)
#### 在方法命名後面加 `!` (可加可不加)
例：`rental!` 
1. 通常代表一個行為，要做某件事情，增加方法的語意特性
2. 在大型專案中加 `!` 也代表該方法需要注意，可前往手冊查閱
3. [方法加驚嘆號解釋 (英文)](https://stackoverflow.com/questions/612189/why-are-exclamation-marks-used-in-ruby-methods?answertab=active#tab-top)
[方法加驚嘆號解釋 (中文)](https://medium.com/@chaowu.dev/ruby-methods-%E5%BE%8C%E9%9D%A2%E6%9C%89-%E9%A9%9A%E5%98%86%E8%99%9F-exclamation-marks-c0468875a4bd)


### Timecop
* Timecop 通常用來應用在測試時模擬不同時間行為的套件
* 少許用法參考
![](https://i.imgur.com/OIQObQJ.png)


```ruby=
class Bike
  def rent!
    @rent_at = Time.now  #Time.now是ruby內建方法
    @return_at = nil
    #前一個人還車時間要歸零
  end

  def return!
    @return_at = Time.now
  end

  def returned?  #判斷是否還車
    @return_at == nil
  end

end
```
在 RSpec 裡面如果設定參數時名字設定成 `subject`，會直接帶入....之後再補
(測試的方法中的名字跟創造出來的實體直接帶入)

### 補充
[龍哥作法](https://github.com/kaochenlong/tdd-youbike/tree/finish)
[Hash值取用方法](https://ruby-doc.org/core-2.7.2/Hash.html)


---
## 建立 MVC 中的 Model

小幫手 `form_for` View Helper，為某個 model 做表格，取代傳統的html寫法
[View Helper介紹](https://railsbook.tw/chapters/15-layout-render-and-view-helper.html)

rails 的 model 會伴隨著 table 資料表產生
model 幫忙翻譯成資料庫（database）語言寫進對應的資料表（table）
>[詳情參照0329筆記](https://hackmd.io/PqieyNqYQtSc4d8x-6H0vQ)

### 檔名建立慣例及 Model & table 存在關係
|檔案名稱| Model | table 資料表|
|:-----:|:-----:|:----:| 
|小寫蛇式單數| 大寫駝峰 | 小寫蛇式複數 |
|book_store.rb|BookStore|book_stores|

Model | table 資料表| 說明
:-----:|:----:|:----
V|V|一般狀況，Model從資料庫裡拿資料
V|X|資料來源不是資料庫 (可能是檔案)
Ｘ|Ｖ|資料不需要被 Model 存取
~~X~~|~~X~~|~~不會有這種狀況，表示根本不需要~~

* 額外補充
  * terminal 中輸入 `$ rails c` (rails console)
  * pluralize 轉成複數的方法
  * underscore 加底線的方法
  * singularize 轉成單數的方法
  * camelize 轉成駝峰寫法的方法
  * 範例 ： ``'book'.pluralize``



* CoC = Convention over Configuration 慣例優於設定
盡量使用慣例



---


### Migration 
- 遷徙的意思 
- 處理的是 table 規格(欄位資訊)上的新增、修改、刪除
- 資料庫伺服器或資料庫文件會根據 migration 檔處理規格並儲存資料
- 用來描述資料庫的成長歷程
- 裡面的資料是文字檔，所以可做版控
- 建立 table 的方法：**migration**
```shell=
$ rails g migration (table名稱)
  # 建立 migration 檔 (建立 table 資料表)

$ rails g model restaurant title address tel email description:text
  # 建立 model 檔和 migration 檔並產生連結
  # 內容為字串 (string) 的話可以省略不寫
  # 原為 $ rails g model restaurant title:string address:string tel:string email:string description:text
```
* 總共會產生兩個檔: 一個 model 和一個 migration
![](https://i.imgur.com/XYSaKPA.png)

* 在 `專案資料夾/db/migrate/` 裡面看得到建立起來的 `migration`
  * create_table：預設會產生流水號 (`t.string :id`)
  * `t. timestamps` : 會建立出兩個欄位 `t.datetime "created_at"` / `t.datetime "updated_at"`

* 建立資料表格 (用 migration 建立相對應的資料檔)
```shell=
$ rails db:migrate
```

* `schema.rb` --> 根據資料庫自動產生，為資料庫描述檔，透過這個檔案來記錄所有更動

#### ==沒事不要刪資料庫==

Note：資料庫不能做管控的原因?
因為常用的資料庫通常是個獨立的系統，不是文字型檔案，所以沒辦法做版本控制
目前用的是 sqlite (檔案式資料庫)，測試用所以版控沒有意義，正式上線通常會用 PG （PostgreSQL）或是 MySQL => 會有個 Dump 功能直接做資料備份

`$rails db:rollback`：返回上一步（不要亂用）
![](https://i.imgur.com/QD9Eanm.png =x200)


## 用 rails 產生表單
- 使用 **Action View Form Helpers**
- [手冊連結](https://guides.rubyonrails.org/form_helpers.html)
- 起手式：form_for(model 名稱) do |f|  (參數名稱可自行調整，在這邊通常會用 f 代表 form)
- 加入欄位：
  - .label
  - .text_field
  - .text_area
```ruby=
<%= form_for(Restaurant.new) do |f| %>   # 後面的 f 是 form 的意思
  <%= f.label :title %>
  <%= f.text_field :title %>

  <%= f.label :tel %>
  <%= f.text_field :tel %>

  <%= f.label :email %>
  <%= f.text_field :email %>

  <%= f.label :address %>
  <%= f.text_field :address %>

  <%= f.label :description %>
  <%= f.text_area :description %>
  
  <%= f.submit '這裡可加想顯示的文字'%>
<% end %>
```

## 在 erb 檔內套用 CSS 樣式
- erb 檔是融合 ruby 及 html 兩種語法的檔案，可加入 tag 做語意及樣式設定
   - 例：用 `<div> </div>` 把 `<%= .... %>` 包起來
### 套用 CSS 檔或 SCSS 檔
- 檔案放置位置：`app/assets/stylesheets/`
- 路徑設定：`app/assets/stylesheets/application.scss`
```css==
 *= require_tree . 
 
 將stylesheets裡所有的檔案打包成一包一次載入
 會按照英文字母順序載入

 *= require '檔名' 
 僅載入指定檔案
 
 如果要註解 tree . 的話，把 = 拿掉
```
```css=
/*巢狀Scss*/
form {
  .field {
    display: flex;
    flex-direction: column;
    padding-top: 0.5em;

    label {
      font-size: x-small;
    }

    input[type=text] {
      border: 1px solid #ccc;
      padding: 4px;
      border-radius: 5px;
    }
  }
}
```
## Rails 自動建立 CRUD routes
- Create Read Update Delete(Destroty)
- 在 `routes.rb` 中寫入 `resources (:controller)`
  - 例： resources :restaurants

![內建resources :restaurants](https://i.imgur.com/zYxTgax.png =1200x)
  - 在 Helper Path/Uri 裡面若沒有顯示，表示同上
  - 內建增加７個方法，８個路徑
  - resource 沒有 s，僅會生成 7 個路徑，無 id，但適合個體，例如：購物車
  - [詳細 routes 說明](https://railsbook.tw/chapters/11-routes.html)
  - 詳細的路徑對照表可輸入指令查詢： `$ rails routes`
- 比較不同方法建立出的路徑：(待確認)

|方法組合|產生方法|產生路徑|說明
|:---:|:---:|:---:|:---|
|resources :複數名詞| 7|8 | 產生的 path 跟 controller 會用複數名詞
|resources :單數名詞| 7| 8|產生的 path 跟 controller 會用單數名詞
|resource :單複數名詞| 7|7 | 無 ID 屬性、無 index action

- 生成之路徑：

|HTTP verb(method)|Controller#Action|
|:-----:|:-----:| 
|GET|restaurant#index|


- 效果與直接自行設定路徑相同
- 可在後面追加指令 only 或是 except
  - 範例
    -  `only: [:index, :show]` => 只建立兩個 action (index 跟 show)
    -  `except: [:index]` => 除了 :index 這個 action，其他所有 action 都建立



[先前CRUD補充筆記 - 116行](https://reurl.cc/g8E3xb)

運算的東西最好不要在 view 裡面處理，盡量都在 controller 裡做
在 controller 中建立新實體，再從 view 裡呼叫實體變數

有些東西可以直接建立網頁讓使用者連上，不用通過 MVC 架構
- 放置地點： `/public/` 或是 `／public/packs/` 

主要放置靜態頁面及資料，例：
1. 404.html
2. 422.html
3. 500.html
4. about.html (如果不會改的話)
5. logo or icon

![](https://i.imgur.com/AP2LQVv.png)


---
## 補充
* [DB browser for SQlite](https://sqlitebrowser.org)
* [<%= > 與 <% > 的差別 ( 英文 ) ](https://stackoverflow.com/questions/7996695/what-is-the-difference-between-and-in-erb-in-rails)
* [Scss](https://sass-lang.com/)
* RESTful 架構網路 ==面試官超級愛問，建議自己寫文章放在部落格==
  * [WIKI 連結](https://bit.ly/31BBnjl)
* 開啟正式模式指令（上線）：`$ rails server -e production`
  開發者模式：`$ rails server` 或是 `$ rails s`
* rails prefix 用法
* member 跟 collection
* shallow: true
* form_for vs. form_with

---
### 連假練習題
1. 只要嘗試做完第13章即可：[參考連結](https://railsbook.tw/chapters/13-crud-part-1.html)
2. 盡可能壓縮在30分鐘內完成 (挑戰看看吧！）
==要錄影!== 
