Bạn có chắc chắn muốn xóa bài viết này không ?
Bạn có chắc chắn muốn xóa bình luận này không ?
Skip callback trong Rails model
Hãy tưởng tượng: bạn là một tín đồ của Rails và DHH. Bạn thần tượng majestic monolith và luôn dùng callback để thực hiện các tác vụ liên quan đến persistence thay vì service object. Bạn gửi notification cho user ngay khi một transaction được tạo ra giống y như được chỉ dạy:
class Transaction < ActiveRecord::Base
belongs_to :user
after_create :create_notification
private
def create_notification
Notification.create! transaction: self, recipients: user
end
end
Một ngày nọ, bạn nhận được một yêu cầu từ khách hàng cần tạo transaction dạng cash, và bạn sử dụng STI ngay lập tức:
class CashTransaction < Transaction
end
Nhưng sếp bạn lại bảo là không nên gửi notification cho khách hàng với transaction này, vậy giờ bạn phải làm sao?
Sử dụng ActiveRecord::Base.suppress
DHH cũng gặp vấn đề như bạn, nên anh ấy đã nghĩ ra một cách cực kỳ thông minh sáng lạng, ấy là tạo ra phương thức .suppress
, và bạn ngay lập tức copy về:
module Chargable
def charge(user)
Notification.suppress do
# Copy logic that creates new transactions that we do not want triggering Notifications
end
end
end
Tuy nhiên, chỉ Rails 5.1 mới có thể làm vậy, và rất xui là project của bạn đang ở Rails 4. Và bạn không thể thuyết phục sếp cho upgrade Rails chỉ vì lý do vô cùng cỏn con như vậy.
Sử dụng ActiveRecord::Base.skip_callback
Rất may là trước khi DHH tài ba nghĩ ra suppress
, bà con đã thấy trước tình trạng này và tạo ra skip_callback
, vậy bạn có thể dễ dàng bỏ qua cái callback này chỉ với:
class CashTransaction < Transaction
skip_callback :create, :after, :create_notification
end
Ngoài ra bạn còn tìm ra rất nhiều cách khác:
Hoặc dùng tham số chỉ định
class Transaction < ActiveRecord::Base
after_create :create_notification, if: -> { !is_a?(CashTransaction) }
end
Hoặc f*** magic, sử dụng kế thừa như bình thường:
class Transaction < ActiveRecord::Base
private
def create_notification
# do not send anything to user
end
end
Và cách tốt nhất:
May mắn làm sao, bạn không phải là tín đồ của DHH, và hẳn là bạn đã tạo ra một PORO object để lo chuyện persist transaction và không bao giờ phải lo về chuyện skip callback vớ vẩn này.







