接著上一篇我們繼續說明用 ORM 來操作 CRUD 的部分 關於讀取的部分還可以怎麼去找到,還有後面的 update 及 delete 的說明。
更精準的讀取 find & find_by & Where
find & find_by
用 find 來找 id
Model.find(:id)
find_by 可以找特定欄位的資訊是否有對應的資料
Model.find_by(欄位名: 值)
兩者的差異:
- find 只能找 id,find_by 可以找任何資料表內的東西
- find 找不到會出錯, find_by 只會回傳 nil
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | 3.0.0 :001 > a1 = Article.find(1)Article Load (0.2ms)  SELECT "articles".* FROM "articles" WHERE "articles"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
 => #<Article id: 1, title: "文章1", content: "進入ruby世界說hello world", created_at: "2022-10-03 12:41:21.8330...
 
 3.0.0 :002 > a2 = Article.find_by(id: 2)
 Article Load (0.3ms)  SELECT "articles".* FROM "articles" WHERE "articles"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
 => #<Article id: 2, title: "文章2", content: "CRUD是什麼?", created_at: "2022-10-04 09:31:49.206583000 +0000",...
 
 3.0.0 :003 > a2 = Article.find_by(title: "文章2")
 Article Load (0.3ms)  SELECT "articles".* FROM "articles" WHERE "articles"."title" = ? LIMIT ?  [["title", "文章2"], ["LIMIT", 1]]
 => #<Article id: 2, title: "文章2", content: "CRUD是什麼?", created_at: "2022-10-04 09:31:49.206583000 +0000",...
 
 | 
找不到資料時的差別
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | 4.3.0.0 :001 > a3 = Article.find_by(id: 3)Article Load (0.3ms)  SELECT "articles".* FROM "articles" WHERE "articles"."id" = ? LIMIT ?  [["id", 3], ["LIMIT", 1]]
 => nil
 
 4.3.0.0 :002 > a3 = Article.find(3)
 Article Load (0.3ms)  SELECT "articles".* FROM "articles" WHERE "articles"."id" = ? LIMIT ?  [["id", 3], ["LIMIT", 1]]
 Traceback (most recent call last):
 1: from (irb):13:in `<main>'
 ActiveRecord::RecordNotFound (Couldn't find Article with 'id'=3)
 3.0.0 :014 >
 
 | 
where
where 可以搭配一些篩選條件,比如過 id > 1,內容包含某些資料之類的條件等等,
我們再建立第 3 筆文章資料,然後透過 where 篩選 id > 1 看看吧。
| 12
 3
 4
 5
 6
 7
 
 | 3.0.0 :001 > Article.allArticle Load (0.3ms)  SELECT "articles".* FROM "articles"  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">, #<Article id: 3, title: "文章3", content: "MVC是什麼?", created_at: "2022-10-04 10:10:05.905998000 +0000", updated_at: "2022-10-04 10:10:05.905998000 +0000">]>
 
 4.3.0.0 :002 > Article.where("id > 1")
 Article Load (0.4ms)  SELECT "articles".* FROM "articles" WHERE (id > 1)  LIMIT ?  [["LIMIT", 11]]
 => #<ActiveRecord::Relation [#<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">, #<Article id: 3, title: "文章3", content: "MVC是什麼?", created_at: "2022-10-04 10:10:05.905998000 +0000", updated_at: "2022-10-04 10:10:05.905998000 +0000">]>
 
 | 
可以看到根據條件就撈出 id=2、id=3 兩篇文章的資料。
Update 更新
用 save 更新
先找到要的資料,然後修改欄位數值,再用 save 更新
| 12
 3
 
 | a1 = Article.find_by(id: 1)a1.title = "第一篇文章"
 a1.save
 
 | 
使用 update_attribute
只更新單一欄位的值 (attribute 是單數),注意會跳過驗證
| 1
 | a1.update_attribute(:title, "第一篇文章")
 | 
使用 update & update_attributes
兩個方法只是名稱不同,都可一次更新多個欄位,且不需要再呼叫 save 方法
| 12
 
 | a1.update(title: "第一篇文章", content: "你知道要怎麼印出'hello world'嗎?")a1.update_attributes(title: "第一篇文章", content: "你知道要怎麼印出'hello world'嗎?")
 
 | 
實際在 console 裡面操作的情形
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 
 | 3.0.0 :001 > a1 = Article.find(1)(0.4ms)  SELECT sqlite_version(*)
 Article Load (0.1ms)  SELECT "articles".* FROM "articles" WHERE "articles"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
 => #<Article id: 1, title: "文章1", content: "進入ruby世界說hello world", created_at: "2022-10-03 12:41:21.8330...
 
 3.0.0 :002 > a1.update_attribute(:title, "第一篇文章")
 TRANSACTION (0.1ms)  begin transaction
 Article Update (0.7ms)  UPDATE "articles" SET "title" = ?, "updated_at" = ? WHERE "articles"."id" = ?  [["title", "第一篇文章"], ["updated_at", "2022-10-04 10:20:44.717780"], ["id", 1]]
 TRANSACTION (0.9ms)  commit transaction
 => true
 
 3.0.0 :003 > a1.title = "改回文章1"
 => "改回文章1"
 
 3.0.0 :004 > a1.save
 TRANSACTION (0.1ms)  begin transaction
 Article Update (0.7ms)  UPDATE "articles" SET "title" = ?, "updated_at" = ? WHERE "articles"."id" = ?  [["title", "改回文章1"], ["updated_at", "2022-10-04 10:21:31.485894"], ["id", 1]]
 TRANSACTION (1.0ms)  commit transaction
 => true
 
 | 
Delete 刪除
刪除有 delete 及 destroy 兩種方法,可以將資料刪除。
| 12
 3
 4
 5
 6
 7
 
 | a1 = Article.find_by(id: 1)a1.destroy
 a1.delete
 
 
 Article.destroy(1)
 Article.delete(1)
 
 | 
終端機操作的顯示
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 
 | 3.0.0 :001 > a1 = Article.find(1)Article Load (0.3ms)  SELECT "articles".* FROM "articles" WHERE "articles"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
 => #<Article id: 1, title: "改回文章1", content: "進入ruby世界說hello world", created_at: "2022-10-03 12:41:21....
 
 3.0.0 :002 > a1.destroy
 TRANSACTION (0.1ms)  begin transaction
 Article Destroy (0.7ms)  DELETE FROM "articles" WHERE "articles"."id" = ?  [["id", 1]]
 TRANSACTION (0.9ms)  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-04 10:21:31.485894000 +0000">
 
 3.0.0 :003 > Article.delete(2)
 Article Destroy (1.9ms)  DELETE FROM "articles" WHERE "articles"."id" = ?  [["id", 2]]
 => 1
 
 3.0.0 :009 > a2 = Article.find(2)
 Article Load (0.3ms)  SELECT "articles".* FROM "articles" WHERE "articles"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
 Traceback (most recent call last):
 1: from (irb):9:in `<main>'
 ActiveRecord::RecordNotFound (Couldn't find Article with 'id'=2)
 
 | 
destroy 跟 delete 的差別:
- destroy 方法執行的時候,會執行完整的回呼(Callback)
- delete 方法直接執行 SQL 的 delete from 語法,不會進行任何回呼。
參考資料:
- Rails Guide
- 為你自己學 Ruby on Rails