# 手刻一個軟刪除的機制 會完成: 1. 軟刪除功能 2. 搜尋過濾被刪除的物件 3. 復原被軟刪除物件 跟 `paranoia` 一樣要先給 table `deleted_at` 欄位,再做以下動作 1. 軟刪除功能 第一步把 paranoia 給的軟刪除方法改成自己的方法,這裡我改成 my_acts_as_paranoid ```ruby class Book < ApplicationRecord my_acts_as_paranoid end ``` 接著在 Book 的上一層 ApplicationRecord 加上這個類別方法 ```ruby class ApplicationRecord < ActiveRecord::Base def self.my_acts_as_paranoid end end ``` 為了判斷這個類別是否啟動軟刪除功能加上一個類別變數,在自己的類別方法中改變它 ```ruby class ApplicationRecord < ActiveRecord::Base @@soft_destroy = false def self.my_acts_as_paranoid @@soft_destroy = true end end ``` 然後把原本 destroy 方法的內容改為更新 deleted_at ```ruby class ApplicationRecord < ActiveRecord::Base . . . def destroy @@soft_destroy ? self.update(deleted_at: Time.now) : super end end ``` 這時候如果用 rails console —sandbox 測試,會發現確實有把刪除改為更新,但用 Book.all 還是可以找到這筆資料,所以再來要做搜尋過濾功能 2. 搜尋過濾被刪除的物件 - 第一個方法是複寫原本的搜尋方法 ```ruby class ApplicationRecord < ActiveRecord::Base . . . def self.all @@soft_destroy ? self.where(deleted_at: nil) : super end end ``` 這時候測試會發現錯誤 ```ruby . . . SystemStackError (stack level too deep) ``` 搜尋的動作進入迴圈 改用 scope 的做法試試看,把 scope 放在類別方法中避免影響到其他沒有設定軟刪除的 model ```ruby class ApplicationRecord < ActiveRecord::Base . . . def self.my_acts_as_paranoid @@soft_destroy = true default_scope { where(deleted_at: nil) } end . . . end ``` 可以成功過濾掉被軟刪除的物件 ```ruby 2.6.0 :001 > Book.all (0.2ms) begin transaction Book Load (0.3ms) SELECT "books".* FROM "books" LIMIT ? [["LIMIT", 11]] => #<ActiveRecord::Relation []> ``` 3. 復原被軟刪除物件 做法跟刪除一樣,只要更新 deleted_at 就可以了 ```ruby class ApplicationRecord < ActiveRecord::Base . . . def restore self.update(deleted_at: nil) if @@soft_destroy end end ```
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up