Những thứ bạn có thể lưu được với PaperTrail
Bài đăng này đã không được cập nhật trong 5 năm
Khi sử dụng PaperTrail để lưu log, ngoài việc muốn biết bản record được update những attributes nào thì bạn lại càng muốn biết ai là người đã update/create/destroy hay chỉ đơn giản là bạn muốn thêm các thuộc tính khác có thể lưu lại của 1 record. Hãy tìm cách để thực hiện chúng.
Trước tiên phải add gem PaperTrail vào project đã https://github.com/paper-trail-gem/paper_trail
1. Ai đã thay đổi record?
Mặc định PaperTrail sẽ có thuộc tính whodunnit
để lưu id của người thay đổi, và cũng cung cấp cho bạn 1 callback. Nếu trong controller có method current_user
thì callback sẽ thực hiện assign current_user.id
vào trường whodunnit
.
# callback
class ApplicationController
before_action :set_paper_trail_whodunnit
end
# Tells PaperTrail who is responsible for any changes that occur.
def set_paper_trail_whodunnit
if ::PaperTrail.request.enabled?
::PaperTrail.request.whodunnit = user_for_paper_trail
end
end
# Returns the user who is responsible for any changes that occur.
def user_for_paper_trail
return unless defined?(current_user)
ActiveSupport::VERSION::MAJOR >= 4 ? current_user.try!(:id) : current_user.try(:id)
rescue NoMethodError
current_user
end
Ơ.... thế nếu controller của bạn không có method current_user
mà là 1 method khác lưu user hiện tại đang đăng nhập thì sao? Override method user_for_paper_trail
lại là được, ví dụ:
def user_for_paper_trail
return unless defined?(current_member)
ActiveSupport::VERSION::MAJOR >= 4 ? current_member.try!(:id) : current_member.try(:id)
rescue NoMethodError
current_member
end
2. Associations
Muốn theo dõi hay thống nhất các association
(tạm dịch các mối quan hệ) ta sử dụng thêm gem này
Cái này mình chỉ hiểu được một phần đó là "Nếu record cha và record con đều được update cùng 1 lần thì với việc sử dụng PaperTrail-AssociationTracking(PT-AT) thì ta có thể thống nhất lại các bản ghi như trước transaction"
class Location < ActiveRecord::Base
belongs_to :user
has_paper_trail
end
class User < ActiveRecord::Base
has_one :location
has_paper_trail
end
user.name # dinvvan
user.location.address # Số 1 Lương
User.transaction do
user.location.update_attributes address: "BacNinh"
user.update_attributes name: "DangVan"
end
t = user.versions.last.reify(has_one: true)
t.name # dinvvan
t.location.address # "Số 1 Lương", instead of "BacNinh"
Vậy là nó sẽ restore
lại bản ghi trước khi thực hiện transaction
Ở đây ta chỉ cần lưu ý là
- Has-One association thì option của method
reify
làhas_one:true
- Has-Many-Through association thì là
has_many: true
- Belongs-To association là
belongs_to: true
3. Storing Metadata
Bằng cách sử dụng Model Metadata hay Controller MetaData chúng ta có thể thêm các cột cho bảng versions
example:
Model Metadata
Class Song < ActiveRecord::Base
has_many :playlists
has_paper_trail(
meta: {
singer: :singer_id,
views: :total_views,
}
)
def total_views
200
end
end
Sử dụng ở controller Metadata from Controllers
class ApplicationController
def info_for_paper_trail
{ ip: request.remote_ip, user_agent: request.user_agent }
end
end
Nâng cao hơn chút nữa, ta có một ví dụ nhỏ
singer_id
là một thuộc tính của Song
để biết là người hát bài hát đó và PaperTrail nó đã mặc định sẽ lưu nó rồi. Nhưng mà vấn đề đặt ra là nếu bạn muốn lấy ra versions của 1 ca sĩ cụ thể (singer); nếu không dùng metadata bạn sẽ phải thống nhất lại bảng version
để tìm ra những versions thuộc về ca sĩ đó => bất khả thi. Vậy thì dùng metadata
thì có gì gọi là khả thi?
Đơn giản là metadata sẽ tìm ra những version bạn muốn nếu bạn sử dụng nó )
PaperTrail::Version.where(singer_id: singer_id) => #<...
Cảm ơn bạn đã đọc và chúc bạn có thêm được một vài thông tin bổ ích.
All rights reserved