接著上一篇我們繼續說明用 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
1 2 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",...
|
找不到資料時的差別
1 2 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 看看吧。
1 2 3 4 5 6 7
| 3.0.0 :001 > Article.all Article 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 更新
1 2 3
| a1 = Article.find_by(id: 1) a1.title = "第一篇文章" a1.save
|
使用 update_attribute
只更新單一欄位的值 (attribute 是單數),注意會跳過驗證
1
| a1.update_attribute(:title, "第一篇文章")
|
使用 update & update_attributes
兩個方法只是名稱不同,都可一次更新多個欄位,且不需要再呼叫 save 方法
1 2
| a1.update(title: "第一篇文章", content: "你知道要怎麼印出'hello world'嗎?") a1.update_attributes(title: "第一篇文章", content: "你知道要怎麼印出'hello world'嗎?")
|
實際在 console 裡面操作的情形
1 2 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
兩種方法,可以將資料刪除。
1 2 3 4 5 6 7
| a1 = Article.find_by(id: 1) a1.destroy a1.delete
Article.destroy(1) Article.delete(1)
|
終端機操作的顯示
1 2 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