+5

Transactions trong Rails

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

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí