Transactions trong Rails
Bài đăng này đã không được cập nhật trong 6 năm
Transaction là tổ hợp của các hành động nhỏ như tạo các bản ghi trong database, thường hay được kết hợp với việc gọi một API bên ngoài. Ví dụ khi xây dựng ứng dụng ghi chép, một vài người muốn thêm dữ liệu và không thành công, đó chưa phải điều gì quá tồi tệ nhưng hãy tưởng tượng trường hợp bạn muốn tính tiền trên store online và sai ở đâu đó. Khi sai ở đâu đó trong chuỗi hành động, bạn có thể sẽ muốn hoàn tác các thay đổi và bắt đầu lại bằng cách yêu cầu user nhập thông tin và bắt đầu quá trình một lần nữa. Bạn sẽ phải lo việc xóa hết các dữ liệu đã tạo trong quá trình thất bại trước đó, hoặc bạn cũng có thể sử dụng Transaction trong Rails
Tổng quan về Transactions
Cách viết transaction
Bạn chỉ cần gọi .transaction
trong Model.
Order.transaction do
@order.charge_credit_card!
@user.order_histories.create!(@order)
end
@order.transaction do
@order.charge_credit_card!
@user.order_histories.create!(@order)
end
ActiveRecord::Base.transaction do
@order.charge_credit_card!
@user.order_histories.create!(@order)
end
Khi có lỗi xảy ra
Một điều vô cùng quan trọng cần nhó là chúng ta có thể rollback transaction chỉ bằng việc bắt lỗi. Thay vì dùng phương thức find_by
bên trọng block transaction, chúng ta có thể dùng find_by!
để đảm bảo rằng khi có gì đó bị lỗi, ứng dụng của bạn có thể ném ra lỗi. Sau khi transaction rollback, lỗi sẽ được ném ra khỏi block transaction để chúng ta có thể bắt lỗi.
Nếu bạn muốn rollback trong âm thầm thì đơn giản là bắt lỗi ActiveRecord::Rollback
bên trong block transaction.
Transaction callbacks
Có 2 loại callbacks thường được dùng cho transaction
After commit
after_commit
callbacks được gọi đến mỗi khi saved hoặc destroyed một bản ghi sau khi transaction đã được commit vào cơ sở dữ liệu. Hãy xem một ví dụ:
class User < ActiveRecord::Base
after_commit :log_user_activity
...
def log_user_activity
Rails.logger.info("User #{id} was updated")
end
end
After rollback
after_rollback
callback được gọi đến mỗi khi save hoặc destroy một bản ghi sau khi transaction bị rolled back. Callback này rất hữu dụng khi bạn muốn ghi lại lý do vì sao transaction không thực hiện được. Bạn có thể chỉ ghi lại một số thuộc tính để sau này kiểm tra lại xem vấn đề nằm ở đâu.
class User < ActiveRecord::Base
after_rollback :log_transaction_status
...
def log_transaction_status
Rails.logger.info("User #{id} was not able to perform action")
end
end
Kiểm soát nhiều hơn
Mình đã đề cập đến cả 2 loại callback đều gọi đến mỗi khi save hay destroy bản ghi nhưng bạn có thể kiểm soát nhiều hơn after_commit
callback. Bạn có thể quyết định muốn gọi phương thức này khi update, create hay destroy.
after_commit :log_user_activity, on: :create
after_commit :log_user_activity, on: :update
after_commit :log_user_activity, on: :destroy
Hoặc gọi một cách ngắn gọn, dễ hiểu hơn
after_create_commit :log_user_activity
after_update_commit :log_user_activity
after_destroy_commit :log_user_activity
Nguồn tham khảo: http://pdabrowski.com/blog/ruby-on-rails/transactions-overview/ http://pdabrowski.com/blog/ruby-on-rails/transactions-callbacks/
All rights reserved