[Rails] Active Record Basic(Model 基本的 CRUD 操作)
速記
- 用
where
取出來的資料會是陣列
目錄
[TOC]
觀念
Active Record 在 Rails 中負責的 Model 部分,主要負責處理商業邏輯和資料。每個資料表(table)大部分都能對應到一個 Rails 中的 Model Class,但是 Model Class 並不是真正的資料表,而是一個負責跟實體的資料表溝通的抽象類別。
Object Relational Mapping(ORM)則是將應用程式中的許多物件和關連性資料庫中的資料表做結合,透過 ORM 可以更容易以物件的方式存取資料庫中的資料而不需直接撰寫 SQL。
-Active Record Basic @ RailsGuides -Ruby on Rails 命名慣例整理
套用 Active Record Model(ApplicationRecord)
只要讓 Model 的 Class 繼承 ApplicationRecord
class User < ApplicationRecord
end
就可以使用基本操作 Model 的方法:
new_user = User.new
new_user.name = 'Aaron'
new_user.save
Console
進入 rails console 後可以使用下面 CRUD 的指令來操作資料庫:
bin/rails c
Create
keywords: create
, new
可以使用 Model class method 中的 create
或 new
來建立一個新的實例。
new 跟 create 的差別,就是 new
方法只是先把物件做出來,尚未存入資料表,因此要手動透過 save
儲存;而 create
方法則是直接把存入資料表。
不管是 new 或 create,在寫入失敗的時候都會回傳一個「內容都是 nil 的 Model 物件」,通常在 Controller 的 Action 裡常會藉此判定資料寫入是否成功。
如果希望在 create 寫敗時就回拋錯誤訊息,可以使用 create!
。
user = User.create(name: 'Aaron', email: 'aaronchen@wavinfo.com', age: 29) # 直接儲存
user = User.new(name: 'PJCHENder', email: 'pjchender@gmail.com', age: 27) # 建立物件實例但尚未儲存
# 一次建立多筆 record
reviewers = User.create([{name: 'Aaron'}, {name: 'Andyyou', email: 'aaronchen@wavinfo.com', age: 29})
程式範例
new
記得最後要用 save
後才會寫入 database:
#####################################################
## 使用 new 方法 - 需要 save ##
#####################################################
# 備註:該物件的 id 值一開 始是 nil ,寫入 save 後才會自動帶值,
# 如果寫入的 id 的值不存在,後面新增的資料 id 會依序最大的 id 往後排
# 如果寫入的 id 值已經存在過,則 save 會出現錯誤
# 直接將要設定的值代入在 new 當中
candidate = Candidate.new(party: "綠黨", politics: "多蓋大樹")
post.save
# 也可以一步一步做
post = Post.new # 建立一個空資料(一列空資料)
# => <Post id: nil, title: nil, created_at: nil, updated_at: nil>
post.title = "Hello everyone!" # 設定 title 的值
# => "Hello everyone!"
post # 輸入 post 會回傳現在該物件的內容
# => #<Post id: nil, title: "Hello everyone!", created_at: nil, updated_at: nil>
post.save # 將物件的資料寫入資料庫中,要記得是 instance object 的 save method(小寫)
# => true
create
不需要用 save
就會寫入 database:
# create 方法有另一個叫做 create! 的方法,兩者差別是當寫入發生錯誤時,create! 會產生例外(Exception)訊息。
Candidate.create(name: "馬應九", party: "綠黨", age: 32, politics: "多蓋大樹") # 沒有填 的欄位,若沒有預設值,會填入 nil
Read and Filter
keywords: all
, includes
, limit
, find
, find_by
, where
, order
, reorder
User.all
Post.includes(:user) # 透過 IN 的方式進行 SQL,節省效能
User.first # 取得 User 資料表的第一筆資料
User.first(3) # 取得 User 資料表的前三筆資料
User.limit(3) # 限制取得的資料筆數
User.last # 取得 User 資料表的最末筆資料
User.find(3) # 找出資料表 User 中 id 為 3 的資料,找不到時會拋錯誤,效能較好
User.find_by(name: 'Aaron') # 根據某欄位進行尋找,找不到時回傳 nil
User.where(name: 'David', occupation: 'Code Artist')
User.where("age > 18", "vote > 3")
User.where.not("age > 18", "vote > 3") # 不要取某些值
User.order(:age) # 按照年齡排序,預設由小排到大
User.order(age: :desc) # 按照年齡排序,由大到小
User.order(:age).reorder(age: :desc) # 如果之前已經有 order 過要再重新排序,需要下 reorder
可以使用方法鍊的方式:
Candidate.where("age > 18")
.where(gender: "female")
.limit(2)
.order(age: :desc)
Post.order(age: :desc).first # 先排序在找出第一個(找出年紀最大者)
不需要擔心連續兩次的 where 方法或是這樣一直連下去會造成多次的查詢,事實上 Rails 在處理這行語法的時候,是先整行語法解讀完才向資料庫進行查詢。
Active Record Query Interface @ RailsGuides
Update
keywords: save
, update
, update_attribute
, update_attributes
, Model.update_all
save
:預設會經過驗證(Validation,在稍後的章節會介紹)流程,如果 驗證失敗將無法寫入。如果想要跳過驗證,可加上 validates: false 參數。update
跟update_attributes
其實只是名字不一樣,但事實上是一模一樣的內容。update_attribute
方法會跳過驗證(Validation),等於是save(validate: false)
的效果。save!
,update!
會在資料無法驗證存入時回拋例外錯誤。
user.name = 'Aaron'
user.save # 使用 user.save! 當儲存失敗(或驗證失敗)時會拋出錯誤
user.update(name: 'Aaron') # 使用 user.update! 當儲存失敗(或驗證失敗)時會拋出錯誤
# 一次更新多筆資料的多個欄位
User.update_all "max_login_attempts = 3, must_change_password = 'true'"
程式範例
# 先找出想要更新的對象
post = Post.find(5) # 根據 id 選擇想要更新的資料
# => <Post id: 5, title: "Set id manually", created_at: "2017-02-17 09:16:15", updated_at: "2017-02-17 09:16:15">
儲存資料(save)
# 修改欄位值
post.title = "I want to be updated" # 設定要更新的欄位值
=> "I want to be updated"
post.save # 寫入資料庫
=> true
Post.find(5)
=> #<Post id: 5, title: "I want to be updated", created_at: "2017-02-17 09:16:15", updated_at: "2017-02-17 09:33:14">
以不驗證資料的方式儲存(validate: false)
order.save(validate: false)
更新多個欄位(update, update_attributes)
candidate.update_attributes(name: "陳橘", age: 54)
candidate.update(name: "陳橘", age: 54)
更新單一欄位資料(update_attribute)
不需要在呼叫 save
candidate.update_attribute(:name, "賴神")
更新整個資料表(Model.update_all)
# 這是類別方法(class method)
Candidate.update_all(vote: 0)
重新載入資料表(reload)
order = Order.first
order.reload
Delete, Destroy
keywords: delete
, destroy
, Model.destroy_all
destroy
跟 delete
的差別,在於 destroy 方法在執行的時候,會執行完整的回呼(Callbacks),但 delete 方法僅直接執行 SQL 的 delete from ... 語法,不會觸發任何回呼。
Wavinfo 開發上習慣用
destroy
instance method
user.destroy
user.delete
class method
Candidate.destroy(1) # 刪除編號 1 的資料
Candidate.delete(1) # 刪除編號 1 的資料
Candidate.destroy_all # 刪除資料表所有資料
Candidate.destroy_all("age < 18") # 刪除所有年齡小於 18 的資料
參考資料
- Active Record Basic @ RailsGuides
- Active Record Query Interface @ RailsGuides
- Active Record Validations @ RailsGuides
- Active Record Callbacks @ RailsGuides