Ruby on Rails: Active Record
_今天來點 Active Record!_ 在講述 Active Record 之前,我們先來建立一個基礎概念:ORM Object–relational mapping Object–relational mapping (ORM) 物件關聯映射 物件關聯映射(ORM)是一種軟體設計模式,將資料庫...
今天來點 Active Record!
在講述 Active Record 之前,我們先來建立一個基礎概念:ORM Object–relational mapping
Object–relational mapping (ORM) 物件關聯映射
物件關聯映射(ORM)是一種軟體設計模式,將資料庫中的數據映射到物件導向程式語言中的物件,使開發人員能夠使用物件導向的方式處理數據,而不必直接處理SQL查詢。 用一個圖書館管理系統的例子來說明不使用 ORM 和使用 ORM 之間的差異。
不使用 ORM 的圖書館管理系統:
在不使用 ORM 的情況下,需要手動建立 Table,並編寫 SQL 查詢將資料存到資料庫中或從資料庫中檢索資料。
-
建立 Table
CREATE TABLE books ( id INT PRIMARY KEY, title VARCHAR(255), author VARCHAR(255), publication_year INT ); -
編寫原生 SQL 查詢來插入書的資料
INSERT INTO books (title, author, publication_year) VALUES ('To Kill a Mockingbird', 'Harper Lee', 1960); -
編寫原生 SQL 查詢來檢索書的資料
SELECT * FROM books WHERE author = 'Harper Lee';
在這種情況下,需要自己處理資料庫結構的細節和 SQL 查詢的編寫。
使用 ORM 的圖書館管理系統:
使用ORM,可以更輕鬆地處理資料,並將其映射到物件。
-
Active Record 定義一個書模型(Model)
class Book < ApplicationRecord end -
創建一本新書並保存到資料庫
book = Book.new(title: 'To Kill a Mockingbird', author: 'Harper Lee', publication_year: 1960) book.save -
查詢書的資料:
books_by_harper_lee = Book.where(author: 'Harper Lee')
使用 ORM,可以將資料庫表格映射到模型 (Model),並使用 Model 方法來執行資料庫操作,而不必編寫原生 SQL 查詢或擔心資料庫結構的詳細資訊,使得代碼更容易閱讀、維護和擴展。
在理解完 ORM 之後,接著來看看 Active Record 吧!
Active Record
Active Record 是一個具體的 ORM 實現。他提供了一種方式來定義和操作 Model,隱藏了資料庫操作的細節,允許開發人員使用物件導向語法來處理資料。Active Record 還提供了方法來執行數據庫查詢、新增、更新和刪除記錄,並建立了 Model 和資料表之間的映射關係,而 Model 在 Rails 中處理與資料庫的互動、商業邏輯、驗證。
接續 Active Record 的概念,讓我們來了解如何建立一個新的 Model(模型)並與資料庫關聯。
-
建立
ArticleModel:命名慣例:Model 的命名是單數
rails generate model Article title:string content:text也可以簡寫成:
rails g model Article title content:text這個命令會生成一個新的 Model 文件
article.rb,並創建一個對應的 Migration,用於創建資料表,在這裡會有個叫 articles 的資料表(table),該資料表包含 title 和 content 兩個欄位,分別是 string 和 text 型別。 Migration 檔名會包含時間戳記和表名的相關資訊,且包含create_table方法,用於定義資料表的結構。 -
確認 Model 定義:
app/models/article.rb
class Article < ApplicationRecord validates :title, presence: true end定義
Article的 Model,並在其中添加了一個驗證規則,要求title欄位必須存在。Active Record 驗證是 Ruby on Rails 中的重要功能,允許在保存記錄到資料庫之前對數據進行驗證,以確保數據的完整性和一致性。
-
執行 Migration:
使用以下命令執行 Migration,以建立
articles資料表:確認資料表欄位都符合自己的需求時,要執行 rails db:migrate 才會真正在資料庫中建立相應的資料表! 沒執行就會看到錯誤訊息:
ActiveRecord::PendingMigrationError!rails db:migrate根據 Model 定義在資料庫中創建一個對應的資料表,該資料表包括
title和content兩個欄位, 且檔名會包含時間戳記和表名的相關資訊,且包含create_table方法,用於定義資料表的結構。db/migrate/20231003042828_create_articles.rb
class CreateArticles < ActiveRecord::Migration[7.0] def change create_table :articles do |t| t.string :title t.text :content t.timestamps # t.datetime :created_at # t.datetime :updated_at # 可以思考這個欄位有無需要更新時間功能 end end end -
使用 Model 的方法:
如此,我們可以在 Rails 中使用
ArticleModel 來處理文章相關的操作,例如新增、查詢、更新和刪除文章。# 新增一篇文章 article = Article.new(title: 'Sample Title', content: 'Sample Content') article.save # 查詢文章 articles = Article.where(title: 'Sample Title') # 更新文章 article = Article.find_by(title: 'Sample Title') article.update(content: 'Updated Content') # 刪除文章 article = Article.find_by(title: 'Sample Title') article.destroy
CRUD 新增、讀取、更新與刪除
當使用 Active Record 在 Ruby on Rails 中進行 CRUD(新增、讀取、更新和刪除)操作時,通常使用以下方法:
-
新增(Create)
- 使用
create方法來新增並保存記錄。
article = Article.create(title: 'New Article', content: 'This is the content of the article')-
使用
create!方法也用於新增記錄並保存到資料庫,不過行為不同。如果新增成功,會返回新記錄的實例,但如果出現任何問題,會引發異常(通常是 ActiveRecord::RecordInvalid),並中止操作。 -
使用
new方法新增一個實例,然後調用save方法來保存記錄。
article = Article.new(title: 'New Article', content: 'This is the content of the article') article.savenew跟create的差別:new方法只是先把物件做出來,尚未存入資料表,因此要手動透過save儲存;而create方法則是直接把存入資料表。 - 使用
-
讀取(Read)
- 使用
find方法按主鍵(ID)查找記錄。
article = Article.find(1)- 使用
where方法按特定條件查找多個記錄。
articles = Article.where(category: 'Technology')- 使用
all方法獲取所有記錄。
all_articles = Article.all - 使用
-
更新(Update)
- 使用
update方法來更新記錄。
article = Article.find(1) article.update(title: 'Updated Article Title', content: 'Updated content') - 使用
-
刪除(Delete)
- 使用
destroy方法刪除單個記錄。
article = Article.find(1) article.destroy- 使用
delete方法刪除單個記錄,但不執行回呼或驗證。
article = Article.find(1) article.delete- 使用
destroy_all方法刪除多個記錄。
articles = Article.where(category: 'Obsolete') articles.destroy_all- 使用
delete_all方法刪除多個記錄,但不執行回呼或驗證。
articles = Article.where(category: 'Obsolete') articles.delete_all - 使用
Callbacks 回呼
Active Record 回呼(Callbacks)可以在 Model 的生命週期中定義一些方法,這些方法會在特定事件發生時自動執行。這些事件包括記錄的新增、更新、刪除等。 Active Record 回呼在這些事件之前、之後或在其他特定情況下執行自定義的程式碼,像是:數據驗證、處理圖片上傳、設定默認值、發送通知等。
以下是一些常見的 Active Record 回呼事件:
-
before_save 和 after_save:
before_save回呼在記錄保存到資料庫之前執行,通常用於數據驗證、設定默認值等操作。after_save回呼在記錄成功保存到資料庫之後執行,通常用於記錄日誌、發送通知等操作。
-
before_create 和 after_create:
before_create回呼在創建新記錄之前執行。after_create回呼在成功創建新記錄之後執行。
-
before_update 和 after_update:
before_update回呼在更新記錄之前執行。after_update回呼在成功更新記錄之後執行。
-
before_destroy 和 after_destroy:
before_destroy回呼在刪除記錄之前執行。after_destroy回呼在成功刪除記錄之後執行。
回呼也可以自定義邏輯,例如,你可以使用 before_save 回呼來檢查數據的有效性,或者使用 after_create 回呼來發送一封歡迎郵件給新註冊的用戶。
以下來看另外一個舉例,在 User 模型中定義了一個 before_save 回呼,在保存記錄之前檢查 api_key 是否為空,如果為空,則生成一個新的 API 金鑰。
class User < ApplicationRecord
before_save :generate_api_key
private
def generate_api_key
self.api_key = SecureRandom.hex(16) if api_key.blank?
end
end
Migration 遷移
Migration 遷移是一個描述資料庫的架構長什麼樣子的檔案。
每個遷移透過逐步添加、修改或刪除資料表、欄位和記錄等,Active Record 能夠根據遷移的時間順序更新資料庫結構,使資料庫能夠在任何時間點前進到最新版本。
同時,Active Record 也會維護一個 db/schema.rb 檔案,以保持其與最新的資料庫結構同步。
在執行 rails db:migrate 後,資料表便隨之產生,
可以想到資料表會有 title 與 content 兩個欄位,但實際打開資料表會發現,
多了 id、created_at 跟 updated_at 這三個欄位。
其實在 Migration 檔案中的 t.timestamps,會產生 created_at 跟 updated_at 的時間欄位,分別會在資料「新增」及「更新」的時候,把當下的時間寫入,所以在 Rails 專案中處理資料的時候,大多不太需要煩惱時間的問題。
id 欄位是 Rails 自動幫每個資料表加的流水編號欄位, 這個欄位稱為資料表的主鍵(Primary Key)。 如果你不想要這個主鍵,可以在 Migration 加上 id: false 參數:
class CreateArticles < ActiveRecord::Migration[7.0]
def change
create_table :articles, id: false do |t| # id: false
t.string :title
t.text :content
t.timestamps
end
end
end
如果想在 Model 再多新增欄位呢?
想要在既有的 Model 內,再新增欄位的話, 透過 rails g migration add_subtitle_to_article 新增一個 migration 之後, 藉由新生成的 migration,加上 add_column 方法, 就可以對之前有建立的 Model (Article) 新增欄位!
class AddSubtitleToArticle < ActiveRecord::Migration[7.0]
def change
add_column :articles, :sub_title, :string
end
end
接著再次 rails db:migrate 後,就可以發現資料庫裡面新增了 sub_title 欄位了!
Brief Summary
Active Record 是 Rails 中的 ORM 實現,讓開發人員能夠以物件導向的方式處理資料,而不必直接處理 SQL 查詢。通過定義模型(Model),我們可以執行 CRUD 操作(新增、讀取、更新、刪除),同時使用回呼(Callbacks)來自動執行特定事件。Migration 則允許我們管理資料庫結構的變化,保持資料庫和程式碼的同步。
詳細的內容可以參考Active Record 基礎看更深入的細節!
參考資料
為你自己學 Ruby on Rails - Model [Rails] Active Record Basic(Model 基本的 CRUD 操作) Active Record 基礎