Ruby on Rails Callbacks: DRY model sử dụng Concerns
Bài đăng này đã không được cập nhật trong 6 năm
Bài viết này chia sẻ về một cách hạn chế việc lặp code hay DRY, nếu bạn chưa biết về DRY có thể đọc thêm tại đây Rails AntiPattern: Duplicate Code Duplication (p1)
Khi chúng ta viết một phần mở rộng cho Ruby on Rails model, ActiveSupport::Concern
có thể là một lựa chọn tốt. chúng hoạt động giống như mixin modules
có thể được bao gồm vào trong một lớp, nhưng có thêm một số lợi ích cho Rails model, chẳng hạn như khả năng thêm Callbacks
.
Bài viết này sẽ chỉ cho bạn cách DRY đoạn code của bạn, concern không chỉ thêm các custom methods cho các bản ghi, mà còn thêm Callbacks
kích hoạt khi create, update và delete.
ActiveRecord Callbacks
Callbacks
là các phương thức được kích hoạt khi một số sự kiện nhất định xảy ra trong vòng đời của ActiveRecord model
. Bạn có thể xem danh sách ActiveRecord Callbacks
trên Rails Guide. Một số Callbacks
trong đó:
before/after validations
before/after save/update/destroy
around save/create/update/destroy
after_commit/after_rollback
(được liên kết với các bản ghi trong database/rollbacks)\after_initialize
(khinew
được gọi trên một bản ghi)after_find
(bất cứ khi nàoActive Record
lấy một bản ghi từ cơ sở dữ liệu)after_touch
Bạn có thể thêm vào code của bạn để chạy khi các Callbacks
này được kích hoạt. Một cách để làm điều này là sử dụng một ActiveSupport::Concern
, mà sau đó có thể chia sẻ hay sử dụng trên nhiều model.
Using a Callback in a Concern
Bạn có thể khai báo một Concern bằng cách sử dụng module được extended ActiveSupport::Concern
. Sau đó thêm các phương thức khác mà bạn muốn bao gồm.
module Publishable
extend ActiveSupport::Concern
def email
UserMailer.weekly_summary(self).deliver_now
end
end
Để thêm Concern vào model, bạn include vào như bạn muốn với module vậy. Sau đó, bạn có thể gọi concern đó trong model callbacks
để chúng được chạy khi callback được kích hoạt.
class User < ApplicationRecord
include Publishable
after_save -> { email }
end
Điều này có nghĩa là bạn có thể tạo các bản ghi và gọi phương thức email
của Concern.
Callback after_save
được kích hoạt khi create hoặc update, vì vậy phương thức email
sẽ được gọi cho các phương thức sau:
User.create
User.new.save
User.update
Extracting the Callback into the Concern
Bạn cũng có thể khai báo Concern để gọi các callbacks
khi nó được include vào model. Để làm được điều này chúng ta sẽ sử dụng included
trong Concern.
module Publishable
extend ActiveSupport::Concern
included do
after_create -> { email }
end
def email
UserMailer.weekly_summary(self).deliver_now
end
end
Bây giờ model không còn chứa các đoạn code logic nữa mà Concern sẽ làm điều đó.
class User < ApplicationRecord
include Publishable
end
Testing Callbacks with RSpec
Ví dụ, bạn có một Callback
chẳng hạn như after_save :email
sử dụng Rails ActionMailer
để gửi xác nhận email sau khi user đã được lưu.
class User < ApplicationRecord
after_save -> { email }
def email
UserMailer.confirmation(self).deliver_now
end
end
Một email sẽ được gửi đi khi một bản ghi được lưu trong test của bạn.
Để ngăn chặn điều này, bạn cần stub phương thức này. Tùy vào codebase của bạn, bạn có thể stub cho các file riêng lẻ hoặc toàn bộ test của bạn.
Trong một tệp riêng lẻ, bạn sẽ thêm các phần sau để có thể chạy Rspec:
RSpec.describe User do
subject { FactoryBot.create(:user) }
before do
allow(subject).to receive(:email)
end
... your tests
Hoặc với toàn bộ các file bằng cách thêm phần sau vào file spec_helper.rb
RSpec.configure do |config|
config.before(:each) do
allow_any_instance_of(User).to receive(:email)
end
end
Chú ý: nó có thể gây chậm khi chạy test
Sau đó khi bạn muốn test cho Callbacks
, bạn cần phải tạo bản ghi, đặt expect cho nó, sau đó gọi một phương thức để kích hoạt Callback
.
RSpec.describe User do
describe "#create" do
it "calls the Callback #email" do
record = User.new(params)
expect(record).to receive(:email)
record.save
end
end
end
Thanks for reading!
Nguồn: https://medium.freecodecamp.org/add-callbacks-to-a-concern-in-ruby-on-rails-ef1a8d26e7ab
All rights reserved