# 0329 MVC框架、資料庫、網站建置第一課
###### tags: `Ruby / Rails`
## 前置作業
- 更新 Rails 到 6.1.3.1
- 更新到最新版本```$ gem install rails```
- 安裝指定版本 `$ gem install rails -v 6.1.3.1`
- 建立一個新的 Rails 專案
- 在 Terminal 裡輸入:```$ rails new <專案名稱>```
- 確認可連接上 Server
- 切換到剛剛建立的專案目錄位址
- 執行:`$ rails s`
- 將程式碼推送至 GitHub
- 在 GitHub 上創立新的 Repository (參考之前 Git 課程)
- 按照步驟將專案推送到 GitHub 上
---
## MVC 框架:Model / View / Controller
收到使用者 Request 後的第一步:傳送到 Route 尋找對應路徑
* 設定位置:config/routes.rb

用一張圖來說明 Rails 裡的 MVC 是怎麼運作的,[龍哥的文章](https://railsbook.tw/chapters/10-mvc.html):

> 使用框架的目的:團隊溝通速度較快
---
指定資料庫驅動程式(使用軟體) `$ rails new (專案名稱) -d mysql`
資料庫選擇:postgresql, mysql
次要選擇: mysql, postgresql, sqlite3, oracle, sqlserver, jdbcmysql, jdbcsqlite3, jdbcpostgresql, jdbc
## 資料庫 (database)
資料庫就是**儲存資料的地方**。資料以不重複的方式來儲存許多有用的資訊,讓使用者可以透過查詢、排序、計算等等方法,來更有效率的管理並轉換成有用的資訊。
資料庫之間的不同
oracle 與 sqlserver
oracle 很貴、金融業仍在使用,完整
sqlserver 介面較簡單,需費用
### 開源圈兩大資料庫:
* MySQL
* PostgreSQL 簡稱 pg / PG:不需費用,專案建議使用
* sqlite3 檔案型資料庫、負擔較小
*一般資料庫叫 SQL,職場上也可能會看到 NoSQL
介於 SQL 跟 NoSQL 中間的產品:Mongo DB 可看做一般excel用就好
### ORM = Object–relational mapping 抽象的概念,把物件轉換成 SQL 語法 /
[WIKI 英文說明](https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping)
[WIKI 中文說明 (翻得不好外加資料很少)](https://zh.wikipedia.org/wiki/对象关系映射)
mongoose類ORM,本質上是操作Mongo DB
Rails 目前沒有支援 NoSQL 但未來如果有人寫出驅動程式的話就有可能支援(還是不建議使用,因為 Rails 就是設計給 SQL 使用的)
### 關聯式資料庫(Relational Database Systems)
普遍常見的RDBS有以下非常多種,各自都有優缺點,因應不同公司、產業類型及開發語言等因素,會採用不同的資料庫來使用。
#### 非開源資料庫
- Oracle DB(甲骨文出產,價格高昂,不少金融相關產業的公司會採用此款資料庫)
- SQL Server(微軟出產,許多大公司會使用此款資料庫,有GUI方便使用及操作,每年的授權使用費用也不便宜)
#### 開源資料庫
- MySQL(業界有許多PHP工程師會選擇此款資料庫為主,並搭配由PHP開發而成的phpMyAdmin來使用,可透過瀏覽器來作為操作資料庫的介面)
- PostgreSQL(簡稱pg)
#### 非關聯式資料庫(NoSQL)
NoSQL 資料庫是為特定資料模型而建立,並且具有構建新型應用程式的彈性結構描述。NoSQL 資料庫在開發的容易性、功能性和大規模效能方面廣受肯定。一個一個文件一筆一筆資料各自存在彼此沒有關聯,好處速度快,但不好操作,以key -> value的方式組合,要自己想辦法用出關聯
【補充】NoSQL最知名常用的資料庫:MongoDB
---
### SQL 是什麼
SQL ( Structured Query Language,結構化查詢語言 ),為一種資料庫語言,在資料庫中擔任建立查詢、更新和刪除(CRUD)的範用型標準語言。
簡單來說,拿SQL語法去資料庫找東西。
詳細解釋:[WIKI](https://bit.ly/3szaXdX)
### SQL 92 標準
大部分都有支援,在 1992 年推出的標準,希望大家都能遵守標準,但是 92 共識就是沒有共識,大家還是自己寫自己的。
#### SQL包含了三個部分:
* 資料定義語言(DDL : Data Definition Language)
- 資料操縱語言(DML : Data Manipulation Language)
* 資料控制語言(DCL : Data Control Language)
- 資料定義語言(DDL : Data Definition Language)由 `CREATE`、`ALTER`與 `DROP` 三個語法所組成。
* CREATE 是負責資料庫物件的建立
* ALTER 是負責資料庫物件修改的指令,相較於 CREATE 需要定義完整的資料物件參數
* DROP 則是刪除資料庫物件的指令,並且只需要指定要刪除的資料庫物件名稱即可
#### 常見的幾種語句:
```SQL=
CREATE DATABASE --建立新資料庫
ALTER DATABASE --修改資料庫
CREATE TABLE --建立新資料表
ALTER TABLE --變更(改變)資料表
DROP TABLE --刪除資料表
CREATE INDEX --建立索引(搜索鍵)
DROP INDEX --刪除索引
```
---
### 資料操縱語言(DML : Data Manipulation Language)
資料操縱語言是用於資料庫操作,主要功能即是存取資料,主要有`INSERT`、`UPDATE`、`DELETE` 為核心,因此其語法都是以讀取與寫入資料庫為主。 而其中 `INSERT` 比較特別,其他的用法都需要搭配 `WHERE` 去篩選來存取資料,但他可以不篩選或界定範圍來做資料處理。
* `INSERT`: 將資料插入到資料庫物件中的指令
* `UPDATE`: 指令是依給定條件,將符合條件的資料表中的資料更新為新的數值
* `DELETE`: \自資料庫物件中刪除資料的指令
以上三種主要指令,再加上`SELECT` 查詢指令後,常會用 **CRUD** 的簡寫來代稱,這是由四個單字縮寫而成,分別為**建立**(Create)、**讀取**(Retrieve)、**修改**(Update)、**刪除**(Delete)。中文縮寫亦有人以**增刪改查**來代稱。
### 資料控制語言(DCL : Data Control Language)
以控制使用者的存取權限為主,由 `GRANT` 和 `REVOKE` 兩個指令組成。
---


---
## 資料表 (table)
由多筆資料紀錄(Record)所組合而成
---
### Active Record 設計模式
- 是一種 ORM 產生的框架
- 是一種大師們遇到問題後精鍊出來的『結果』
- 解決問題的手法
- 遇到問題時該怎麼處理的方法
- 把資料庫的資料一筆一筆包成一個物件,並在物件上加上商業邏輯以操作物件,目的是讓資料存取更便利
### Model=廣義的資料抽象概念,不是資料庫
- 透過Active Record模式設計的產物
## 其他
* i18n
* 如果一個應用程式在設計時,可以在不修改應用程式的情況下,根據不同的使用者直接採用不同的語言、數字格式、日期格式等,這樣的設計考量稱為國際化(internationalization),簡稱i18n(因為internationalization的 i~n 之間有18個字母)。
* k8s
* Kubernetes(常簡稱為K8s)是用於自動部署、擴充和管理「容器化(containerized)應用程式」的開源系統。 該系統由Google設計並捐贈給Cloud Native Computing Foundation(今屬Linux基金會)來使用。
#### 語意化版號 (不成文共識)
6.1.0
6 = major:不同軟體(不同框架)
1 = minor:功能升級,但不保證向下相容
0 = patch:小地方修正,向下相容
[參考資料](https://semver.org/lang/zh-TW/)
*Electron:Build cross-platform desktop apps with JavaScript, HTML, and CSS.
像是VScode, Messenger, Teams都是用 Electron做的,未來專案可以考慮做
https://www.electronjs.org
## 「 透過錯誤分析了解網站建立 」
### iChef 實作
*新增一間新餐廳需要哪些資料?
| 餐廳範例| 資料型別 |
| -------- | ----------- |
| 餐廳名稱 | 字串/String |
| 地址 | 字串/String |
| 電話 | 字串/String |
| email | 字串/String |
| 描述 | Text |
* string:一般文字 有固定長度限制
* text binary:可以放到 4GB 大小(依資料庫不同而有不同大小限制)
* Binary: 二進位
* TEXT:文字類型的資料型別,並非二進位。(資料出處為MySQL官網)
---
### [ 狀況 ] 連到網頁,出現沒有 Route 的錯誤訊息
### * 設定 Route
如果沒有設定 Route 的話,嘗試連結會出現下方錯誤畫面

想功能前先想路徑 ```/restaurants```
Routes 列表網址:==名詞 + s== (範例如上面的餐廳s)
- 建立新的 Route:
```ruby=
Rails.application.routes.draw do
get '/restaurants', to: 'a#b'
# 使用 "GET" 方法連到 /restaurants 時
# 會連到 a controller 裡面的 b action
# get ('/restaurants'), { to: 'a#b' } 的縮寫
# to: 'a#b' 是個hash,花括號可省略
end
```
---
### [ 狀況 ] 建立完 Route,出現沒有 Controller 的錯誤訊息
### *建立 Controller

所有 Controller 檔案位置:`app/controllers/`
檔名:books_controller (蛇式) => 方法會變成 BooksController (Rails慣例/雙駝)
檔案位置:`/app/controllers/application_controller/`
```ruby=
class ApplicationController < ActionController::Base
end
```
在實際物件跟最原始層之間有一個距離,如果有共同需要使用的功能就直接加在這層即可,為了彈性
* 若重整後沒錯誤訊息且沒有更新的話,重新開一次伺服器 rails s
---
### [ 狀況 ] 建立完 Controller,出現沒有 action 的錯誤訊息

### *定義 action
#### 讓頁面印出hello
render 是 上層? Rails? 定義的方法
```ruby=
class AController < ApplicationController
def b
render html: 'hello'
#render是rails內建的方法,繼承自Base
end
end
```
> https://api.rubyonrails.org/
> [render方法說明](https://rails.ruby.tw/layouts_and_rendering.html#%E4%BD%BF%E7%94%A8-render)
成功印出訊息

---
### [ 狀況 ] 定義完 action 方法但是沒有實際方法或是建立 Views 底下檔案出現錯誤

### *建立 Views 內資料夾及檔案
換到view_file內,建a的資料夾(a controller)的b.html.erb檔案(b action)

在b.html.erb內編輯

---
#### 小技巧 // VScode 資料夾被群組收合無法正確建檔的調整方式:
1. 到 VScode 調整設定

2. 在設定頁面解除資料夾群組

---
### *可以多個路徑指向同個地方
* 去思考是不是需要為了一個頁面再生一個 controller

```ruby=
# 產生controller generate = g
$ rails generate controller books
$ rails g controller books
# 刪除controller destroy = d
$ rails destroy controller books
$ rails d controller books
# 不論產生or刪除,透過rails的指令會自動生成相對應名稱的controller及檔案
# 但不會幫你放在get上,要記得去加
```
### *Rails 會預設保護 POST 行為送出的數據,因此必須檢查驗證碼
```html=
<!-- 實務上並不這樣使用,龍哥只是為了解說 -->
<form method="post" action="/abc">
<!-- 習慣上token會用hidden類型的隱藏欄位來傳送 -->
<input type="hidden"
name="authenticity_token"
value="<%= form_authenticity_token %>">
.....
</form>
```
如果真的要跳過驗證程序,可加下方的 code,但不建議這麼做
```ruby=
skip_before_action :verify_authenticity_token
```
沒有加上驗證動作時,所出現的錯誤訊息

重新提交表單 => 重整用 POST 連接的頁面會發生的事情
#### 新增資料的頁面通常會直接 redirect_to 其他頁面
```ruby=
def list
# 寫入表單
# redirect 轉址 -> ex.回列表頁
redirect_to '/restaurants'
end
```
### *設定頁面中連結的多種寫法
```html=
<!-- #html #固定路徑 -->
<a href="/new_restaurant">新增餐廳</a>
```
```erb=
<!-- #混搭 -->
<a href="<%= new_restaurant_path %>">新增餐廳</a>
```
⬇︎ 龍哥建議用這個 ⬇︎ (他好像說之後都會這樣用🙃)
```ruby=
#ruby
<%= link_to '新增餐廳', new_restaurant_path %>
```
補充
```ruby=
#ruby #如果連結為 "/user/create" 可以用蛇式寫法表達
<%= link_to '新增使用者', user_create_path %>
```
* 好處一 可以整理得很乾淨
* 好處二 因為是程式的關係,打錯字可以馬上知道
但效能比較差,因為會多一次的方法呼叫
*由於這邊用Ruby寫,在routes那邊也要用Ruby寫
```ruby=
Rails.application.routes.draw do
get '/restaurants', to: 'restaurant#index'
get '/new_restaurants', to: 'restaurant#new'
⥬ post :restaurant_list, to: 'restaurant#index'
# post '/restaurant_list', to: 'restautant#index' (HTML寫法)
end
```
---
```ruby=
#想要找某個方法的定義
method(:days).source_location
```

進到專案位址再 rails console,可簡寫 rails c

確認要找的方法是可以執行的

執行.source_location找到這個方法的定義
然後另開一個新的終端機
使用vim 進入獲得的路徑

使用J、K做上下移動,然後就會獲得這個方法是如何被定義

* 一定要進rails console才能找
* console,可以說是控制台的概念,進去console直接對程式/資料庫做指令
---
比較一般A 、 link_to 還有 path 的優劣
```ruby=
# config/routes.rb
Rails.application.routes.draw do
post :restaurant_list, to: 'restaurant#new', path: '/ccc'
end
```
---
* 提供思路走向圖(?)

* 對照表,可透過打錯路徑獲得,也可用終端機輸入`$rails routes`

* 如果action裡有render這個方法,就不會去找相對應的views,而是直接執行render
