Model

前面的章節有提到過 Model 其實就是一個幫忙與資料庫溝通的地方,他既不是資料庫(Database)也不是資料表(Table),Model 可以當成一個抽象類別,負責跟實體的資料表溝通。

CRUD

先來簡單說文解字一下這四個基本的字,”CRUD”的意義吧!主要是描述下面這四個字。

  • Create (C) 新增,建立資料,將定義好的欄位寫入對應的值
  • Read (R) 讀取,讀取資料,查詢資料的相關內容
  • Update (U) 更新,更新特定欄位的資料
  • Delete (D) 刪除,刪除資料

我們可以透過基本的 ORM 操作來感受一下 rails 如何用到上面的這些操作資料的動作吧,操作前先簡單解釋一下相關的專有名詞,也是許多面試常常會問到的觀念。

ORM?

ORM 是 Object Relational Mapping 的縮寫,翻譯成「物件關聯對映」。如果想要存取資料庫裡的內容,在以前必須自己撰寫資料庫查詢語言(SQL)對資料庫進行查詢,但透過 ORM 的技術包裝之後,可以讓我們用操作「物件」的方式來操作資料庫。

Active Record?

Active Record 是一種設計模式,MVC 中的 Model 就是根據 Active Record 的 模式設計出來的,另外一種常見的說法是 Active Record 是 ORM 的實作方式。

Active Record 的好處

  • 使用物件導向的方式來操作資料表
  • 展現 Model 之間的關係
  • 表示出相關 Model 之間的繼承關係
  • 在存取到資料庫之前驗證資料

用 ORM 方式來操作 CRUD

建立 model

我們先建立一個文章 Article 的 Model,在終端機輸入下面指令就可以建立,同時也定義 2 個欄位給他,分別是

  • string 型態的 title
  • text 型態的 content
1
rails g model Article title:string content:text

會產生對應的資料表,我們可以在 app/db 下面看到 migration 檔案,migration 會記錄建立 table 的經過,具備哪些欄位,我們在輸入 db:migrate 將 table 具現化,才能對裡面的內容進行操作

1
2
3
4
5
6
7
8
9
10
class CreateArticles < ActiveRecord::Migration[6.1]
def change
create_table :articles do |t|
t.string :title
t.text :content

t.timestamps
end
end
end

從上面看似乎還會有 timestamps 這個資料欄位,但其實總共還會多出 idtimestamps ,timestamps 在經過轉換之後,會產生兩個名為 created_at 跟 updated_at 的時間欄位,分別會在資料「新增」及「更新」的時候,把當下的時間寫入,可以作為一個紀錄,讓你知道某筆資料的變動。
id 欄位則是在 Migration 沒辦法看到任何資訊,因為這是 Rails 自動幫每個資料表加的流水編號欄位,也稱為資料表的主鍵(Primary Key)。方便讓你知道目前這個 table 建立過幾筆資料,查找上也會比較方便。

可以從下面預設的 app/db/development.sqlite3 的檔案看到實際所有的欄位

Create 建立

可以從 rails console 裡面來操作實際建立一筆資料,終端機輸入 rails console or rails c 之後
我們可以使用 active record 提供給我們的方法

  1. create
  2. new
    兩者的差別是,new 完需要 save 才會存入資料庫,create 則會直接寫入。
    我們用 create 的方式來看一下。
1
2
3
4
5
6
3.0.0 :001 > Article.create(title:"文章1",content:"進入ruby世界說hello world")
(0.3ms) SELECT sqlite_version(*)
TRANSACTION (0.0ms) begin transaction
Article Create (0.4ms) INSERT INTO "articles" ("title", "content", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["title", "文章1"], ["content", "進入ruby世界說hello world"], ["created_at", "2022-10-03 12:41:21.833091"], ["updated_at", "2022-10-03 12:41:21.833091"]]
TRANSACTION (0.4ms) commit transaction
=> #<Article id: 1, title: "文章1", content: "進入ruby世界說hello world", created_at: "2022-10-03 12:41:21.833091000 +0000", updated_at: "2022-10-03 12:41:21.833091000 +0000">

可以看到上面 有出現 INSERT INTO “articles” 這個 SQL 語法,表示已經將檔案寫入資料庫

Read 讀取

想要取得資料表中的第一筆或最後一筆資料,可使用 firstlast 方法,我們用 last 來讀看看

1
2
3
4
5
6
4.3.0.0 :002 > a1 = Article.last
Article Load (0.5ms) SELECT "articles".* FROM "articles" ORDER BY "articles"."id" DESC LIMIT ? [["LIMIT", 1]]
=> #<Article id: 1, title: "文章1", content: "進入ruby世界說hello world", created_at: "2022-10...

4.3.0.0 :003 > a1
=> #<Article id: 1, title: "文章1", content: "進入ruby世界說hello world", created_at: "2022-10-03 12:41:21.833091000 +0000", updated_at: "2022-10-03 12:41:21.833091000 +0000">

讀取最後一筆 (目前也只有一筆) 資料並且放入變數 a1 中,可以看到顯示出所有這筆資料的欄位及值,除了我們說的定義的欄位之外還有多出那 3 個前面提到的欄位。

我們也用一下 new 方法讓大家看一下,需要再用 save 進行資料的寫入

1
2
3
4
5
6
7
8
9
3.0.0 :001 > a2 = Article.new(title:"文章2", content:"CRUD是什麼?")
(0.6ms) SELECT sqlite_version(*)
=> #<Article id: nil, title: "文章2", content: "CRUD是什麼?", created_at: nil, updated_at: nil>

4.3.0.0 :002 > a2.save
TRANSACTION (0.2ms) begin transaction
Article Create (1.1ms) INSERT INTO "articles" ("title", "content", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["title", "文章2"], ["content", "CRUD是什麼?"], ["created_at", "2022-10-04 09:31:49.206583"], ["updated_at", "2022-10-04 09:31:49.206583"]]
TRANSACTION (0.8ms) commit transaction
=> true

看到 save 之後有回傳一個 true 表示有成功寫入。

也可以來用 first 抓看看我們的資料,先用 Article.all 看一下全部是有兩筆資料,然後可以用 first,也可以用 first(number),括號內可以指定要從第一筆開始抓幾筆。

1
2
3
4
5
6
7
8
9
10
11
3.0.0 :004 > Article.all
Article Load (0.5ms) SELECT "articles".* FROM "articles" /* loading for inspect */ LIMIT ? [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<Article id: 1, title: "文章1", content: "進入ruby世界說hello world", created_at: "2022-10-03 12:41:21.833091000 +0000", updated_at: "2022-10-03 12:41:21.833091000 +0000">, #<Article id: 2, title: "文章2", content: "CRUD是什麼?", created_at: "2022-10-04 09:31:49.206583000 +0000", updated_at: "2022-10-04 09:31:49.206583000 +0000">

3.0.0 :004 > Article.first
Article Load (0.3ms) SELECT "articles".* FROM "articles" ORDER BY "articles"."id" ASC LIMIT ? [["LIMIT", 1]]
=> #<Article id: 1, title: "文章1", content: "進入ruby世界說hello world", created_at: "2022-10-03 12:41:21.833091000 +0000", updated_at: "2022-10-03 12:41:21.833091000 +0000">

4.3.0.0 :005 > Article.first(2)
Article Load (0.3ms) SELECT "articles".* FROM "articles" ORDER BY "articles"."id" ASC LIMIT ? [["LIMIT", 2]]
=> [#<Article id: 1, title: "文章1", content: "進入ruby世界說hello world", created_at: "2022-10-03 12:41:21.833091000 +0000", updated_at: "2022-10-03 12:41:21.833091000 +0000">, #<Article id: 2, title: "文章2", content: "CRUD是什麼?", created_at: "2022-10-04 09:31:49

下篇再來繼續說明一些讀取的方法、更新及刪除的部分。

---

參考資料:

  1. Rails Guide
  2. 為你自己學 Ruby on Rails
  3. wiki ORM