# Ruby(04/14) 五倍紅寶石(第八屆共筆)(2021/8/06)
Rails 比 Ruby 還紅,太方便的基本上都是 Rails 語法。
---
## 存取控制
### public 公開方法
沒有特別寫的都是或是有寫 public 的話,以下都會是公開方法,不用加 end。
規定:無。
### private 私有方法
類別裡面寫一個 private 的話,以下都會是私有方法。
不能在外面呼叫(存取)他,要透過公開方法存取私有方法(遙控器外面的介面去按到裡面的電路板),
如果要用的話把私有方法包在公開方法裡面就可以拿出來用了。
唯一規定:不能指名 receiver 是誰!同血脈的都可以用 => 不能有小數點。
新規定(2.7.0版之後):self 也可以當receiver。
why?
有些功能不想讓外部直接存取,防止別人去用它。
封裝就是把方法關在裡面,變成私有方法。
```rb
class Cat
def hi
self.gossip
end
private
def gossip
end
# 單純指定某方法為 private 也可(少用)
private :gossip
end
```
puts 本身在整個環境內是一個私有方法,也可使用 self.puts 印出後面東西。
- p self.private_methods.sort: 看他本身有甚麼私有方法可用。
### 方法其實是訊息
kitty.hi
kitty 是 receiver = 訊息接收者
.hi 是 message = 發送訊息給訊息接收者
實體收到訊息後,會找他自己或是他的上層 class 有沒有這個訊息可以用,有的話就去他那邊引用過來,沒有就 NoMethodError。
#### 偷吃步
kitty.send(:gossip)
這邊的 gossip 不是方法是符號,可以當參數傳給 send 呼叫。
### protented (少用,別管他)
跟 private 一樣功用,不能在外面呼叫(存取)他,但可以有明確的 receiver。
---
## 繼承
Ruby 是單一繼承的程式語言。
其他語言可能有多重繼承,而鑽石繼承會有不知道該聽誰的的問題。
---
## module 模組
- 命名規定:必須是常數,跟類別一樣。
把模組混到類別裡面,讓他可以用它的功能,也就是偷別人的功能過來用。
```rb
module
def a
end
end
```
### 模組 vs 類別
類別跟模組很像是因為類別就是繼承自模組的。
類別方法數會比模組多,下層繼承上層的祖產,加上自己也有收入。
類別只比模組多了三個方法。
- 差在模組不能:
1. 建立實體(所以用 initialize 也沒意義)
- new:用來建立實體的,可以設定 initialize,也就是他的初始狀態。
- allocate:也可以建立實體,沒辦法設定 initialize,建立出來的實體會忽略 initialize,不會有初始狀態。
2. 繼承上層
- superclass:繼承上層
### ancestors:可印出祖宗十八代,
除了 superclass 也會印出 module,他是印出方法的搜尋路徑,找他是從哪個類別或是模組來的。
### include 外掛進來的模組優先權會比上層類別高。(可參考下面的物件模型圖)
當 cat 呼叫 a 方法時,因為在 C 類別找不到方法,會往上層找,這時候 A 有 include 模組也有自己的上層, 他會優先去找模組內的 a 方法。
```rb
module A
def a
end
end
class B
def a
end
end
class C < B
include A
end
cat = C.new
cat.a
```
### BasicObject vs Object
兩個類別裡面的方法數其實是一樣的,差在 Object 多引用了 kernel module 的方法,而 BasicObject 只有他本身的方法,沒有 include 別的 module。
### include vs extend
- include: 只是引用他,include 進來的因為會被繼承所以會變實體方法。
- extend: 用來擴充功能的,擴充進來的會在這個類別直接增加功能,會變成類別方法。
#開頭的是 Singleton Class,上一堂提到的 Singleton Method 會放在這個類別裡,就是只對這個物件有效的方法,不會透過繼承傳給他生出來的實體。
參考:[Ruby Metaprogramming筆記(3): singleton method與singleton class](https://medium.com/@eggyy1224/ruby-metaprogramming%E7%AD%86%E8%A8%98-3-singleton-method%E8%88%87singleton-class-7523e273e0fb)

### include vs prepend
- include: 參考物件模型圖,會放在那個 class 的上方。
- prepend: 參考物件模型圖,會放在那個 class 的下方。
### namespace
模組裡面包類別時,且類別名相同時可用
用::取用,取到特定類別或模組
```rb
a = A::B::C::D.new
ABC可以是類別或模組,通常會用模組
D一定是類別,只有類別可以new
```
### 很噁心的 Ruby 物件模型

### 物件模型圖:

---
## Rails
- rails new 專案名稱 => 開新專案
- rails s = rails server => 開伺服器
資料夾:
- app:有MVC(重要)
- assets:圖片、css
- channel:即時通訊
- javascript:原本在 assets 裏面,後來被拉出來
- config: 設定檔(重要)
- database:推薦使用 PostgreSQL(開源版)、MySQL 被買走,免費仔只剩社群版(哭哭
- routes:門口阿桑
- db: database (重要)
- migrate:描述資料表長甚麼樣子
- lib:
- rake 的 task
- public:公開頁面(主要放靜態頁面)
- test:寫測試
- Gemfile:
列出這個專案用了哪些套件。
各套件版本,6.1.4,如果變了會怎樣:
- major:6 變成不同軟體了,基本上會不相容
- minor:1 有可能會不相容
- patch:4 基本上都會相容,沒什麼問題
~> 只會更新 patch,不管 major、minor
= 就那個版本
\> 出了比他更新的版本都會更新
- package.json:前端套件
### adapter:轉接頭,透過他讓rails跟database溝通
可在 Gem 搜尋 pg 或 sqllite 下載
### 實作1
要先了解他的運作方式跟為什麼要這麼做才會知道自己下一步要幹嘛,不然很容易迷失自我。
假如我今天在日本要去吉野家吃雞肉丼飯,但我不知道這附近有沒有吉野家,要怎麼辦:
1. 去問路人(Route)吧,他會告訴我吉野家的地址在哪。
2. 接著我照著路人給我的地址走到目的地發現這邊根本沒有吉野家,只有一片空地。
3. 既然沒有那我就自己蓋一間吧(建立常數)。
4. 蓋完之後發現沒有人煮菜,只好請廚師(Controller)煮了(建立方法)。
5. 這時候廚師煮完了,但累到沒力氣裝盤,只好請小弟(View)幫我端上來(網頁顯示成果)。

```rb
0.
我想做一個網站,所以要先建立一個新的專案(new)
rails new 新專案名稱
0.5.
我想看到頁面長甚麼樣子,所以要進入伺服器讓他顯示出來(server)
rails server or rails s => 進入伺服器,進入他提供的網址會看到一堆奇怪的人
若發生以下狀況代表進錯資料夾,必須要進入剛剛建立的資料夾才能進入伺服器,
因為機器很笨,只會找現在這個資料夾有沒有他要的資料(ex:config.ru、Rakefile之類的檔案),
不會進一步看裡面的資料夾有沒有東西。
Description:
The 'rails new' command creates a new Rails application with a default
directory structure and configuration at the path you specify.
You can specify extra command-line arguments to be used every time
'rails new' runs in the .railsrc configuration file in your home directory,
or in $XDG_CONFIG_HOME/rails/railsrc if XDG_CONFIG_HOME is set.
Note that the arguments specified in the .railsrc file don't affect the
defaults values shown above in this help message.
Example:
rails new ~/Code/Ruby/weblog
This generates a skeletal Rails installation in ~/Code/Ruby/weblog.
1.
第一關由 routes 把關 = 門口阿桑 = 路徑對照表
可用 command p 找,比較快,一般放在 config 裡面
我想建立一個頁面叫做 yoman,路徑會是 /yoman ,
把他對應到 hihi controller (放在 hihi 資料夾裡),他可以用 whatsup 這個方法做事
Rails.application.routes.draw do
get "/yoman", to: "hihi#whatsup"
end
to: "hihi#whatsup"這邊的hihi指的是controller的名字,#後面是方法
接著進入路徑 /yoman 會出現錯誤訊息
Routing Error
uninitialized constant HihiController
路徑錯誤,因為我只是叫他去找這個路徑但我還沒建立
目前有個常數 HihiController 還沒被初始化,所以我要去幫他初始化
2.
第二關由 controller 把關
從錯誤訊息看到 HihiController 提示,所以答案應該在 controller,
發現裡面有個預設的 application_controller 檔案
ActionController::Base 使用者不可控制,不能修改裡面的方法
ApplicationController 使用者可控制,讓他去做修改,把共用的方法都放這,
讓我每個頁面都可以用這邊定義的方法
剛剛網頁說沒有 HihiController 常數,
所以就自己建一個 hihi_controller 檔案並讓 HihiController 繼承 ApplicationController,
我的 HihiController 之後就可以用裡面的方法了
(檔案名稱慣例是用蛇式,內部 class 名稱慣例用駝峰式)
class HihiController < ApplicationController
end
3.
第三關一樣由 controller 把關
這時候錯誤訊息變成:
Unknown action
The action 'whatsup' could not be found for HihiController
他說找不到我的動作(whatsup 方法),所以我就自己幫他做一個
class HihiController < ApplicationController
def whatsup
end
end
4.
第四關由 view 把關
這時候錯誤訊息變成:
No template for interactive request
HihiController#whatsup is missing a template for request formats: text/html
NOTE!
Unless told otherwise, Rails expects an action to render a template with the same name
他說沒有 whatsup 這個模板(儲存頁面資料的地方,不會讓 HTML 的標籤顯示出來 = 會套用 HTML 格式)讓他回應
他期待會有一個跟動作(方法)相同名字的模板讓他顯示出來,格式類似 text/html
所以我要幫他創一個名為 whatsup 的模板出來
或是直接在 whatsup 裡面 render html: "hi" 也可以。
去哪創?
因為我想讓他顯示出來,所以可以對應到 view,在裡面建立一個 hihi 資料夾(第一關指定的),並建立 whatsup.html.erb 檔案
(附檔名用 .html.erb 是為了讓 HTML 檔能夠使用 Ruby 語法)
P.S. windows 用戶需停掉 server 再重新啟動才能顯示,MAC 沒有這個問題
補充:
1.Gemfile 檔案裡把 gem 'rack-mini-profiler', '~> 2.0' 給註解掉網頁就不會出現顯示讀取幾秒的提示。
2.檢查 vscode 的設定 compact folder:不要勾,會比較好找檔案
```
### 實作2
- 使用 generate controller 指令會幫我們做兩件事:
1. 建立 controller
2. 建立 views/users 資料夾
```rb
rails g controller rices
1.在 routes 裡面建立 /rices 路徑,給他一個 cook 方法
2.在 rices 建立 cook 檔案
=> 搞定收工
```
---
## database
可以不用進資料庫操作,rails 就會顯示有沒有寫入。
可以把 excel 當資料庫來看,一個 excel 檔裡面有很多資料表,資料表有很多欄跟列,每一列都是一筆使用者的資料。
- Route = 門口阿桑 = 路徑解析
- Model = 翻譯蒟蒻,不是資料庫,放資料庫相關資料及資料邏輯
我可以透過 Ruby 語法跟 Model 溝通,Model 會轉換成 SQL 語言跟資料庫溝通,最後回傳我看得懂的訊息。
會產生 Migration 檔:描述資料表該長甚麼樣子,跟 Git 版控一樣會記錄所有的變動(整個演進過程),但如果直接操作資料庫不會有紀錄。
- View = 資料呈現,畫面相關 = 會回傳 HTML 內容的方法
- Controller = 調度資料,流程控制
### 實作3
套用實作1的例子,從第6點開始是 model 做的事。
假如我今天在日本要去吉野家吃雞肉丼飯,但我不知道這附近有沒有吉野家,要怎麼辦:
1. 去問路人(Route)吧,他會告訴我吉野家的地址在哪。
2. 接著我照著路人給我的地址走到目的地發現這邊根本沒有吉野家,只有一片空地。
3. 既然沒有那我就自己蓋一間吧(建立常數)。
4. 蓋完之後發現沒有人煮菜,只好請廚師(Controller)煮了(建立方法)。
5. 這時候廚師煮完了,但累到沒力氣裝盤,只好請服務生(View)幫我端上來(網頁顯示成果)。
6. 這時候我想說既然我都把吉野家弄出來了就來開店吧。
7. 因為現在疫情還是蠻嚴重的,有客人進來了我想要請櫃台人員(model)幫我做實名制,並且需要記錄客人買了甚麼、花了多少錢(建立 model)。
8. 接著櫃台人員會把他記錄的東西用程式語言(sql語法)輸入到電腦裡(db:migrate)。
- 使用 g model 會幫我們做兩件事:
1. 產生 migrate 檔:負責建資料表
2. 產生 model 檔
```rb
1. 生出 model
rails g model User account password email
model 命名慣例:
大寫 + 單數:User
資料庫內的資料表名稱會轉換成 users,U 變小寫、最後加 s
如果資料型態是 string 可不用寫。
除了 account password email 還會長出一個 id 跟 兩個時間戳記欄位。(共6個)
t.timestamps:
created_at:哪時建立的
updated_at:哪時更改的
2. 用 db:migrate 才能讓他顯示出來(具現化):把剛剛 model 建的資料表移動到資料庫
rails db:migrate
用 SQLite 圖形化介面工具可以去檢視資料庫裏面的 sqlite3 檔案
玩壞的話可以把 sqlite3 資料夾刪掉再重新 db:migrate
rake db:migrate = rails db:migrate (後來才改的)
```
---
[Ruby XMind](https://www.xmind.net/m/uRyuKh)
---
###### tags: `Ruby` `Rails`