Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

Person timeline: normalize PaperTrail changesets across create/update/destroy at read time

Đang mở
#2,250 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
55/100
Loại issue
Tính năng
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Ít trao đổi
Công nghệ
ruby
Lĩnh vực
backend

Hướng nghiên cứu

Bắt đầu với app/views/application/_papertrail_versions.html.erb và reader person-timeline hiện có, sau đó lần theo cách các version của PaperTrail được tải và render. Xác định shared normalizer nên nằm ở đâu, cho cả hai reader đi qua nó, batch-load các whodunnit user trong khi xử lý các actor nil, và thêm các spec bao quát các event create, update và destroy.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

enhancement

Context

We're versioning financial/membership/registration models with PaperTrail (subject_person_id meta) to build a person-scoped timeline. PaperTrail stores diffs asymmetrically by event, so a naive reader has to special-case events:

event object (full state) object_changes (diff)
create nil {field: [nil, new]}
update prior state {field: [old, new]}
destroy final state nil

Destroy events never populate object_changes; the final state lives only in object.

Decision 1 — normalize changesets at read time

Do not force object_changes onto destroy at write time — it duplicates data already in object, is a semantic fiction ([value, nil]), fights PaperTrail defaults, and only half-fixes the asymmetry (create's object is still nil).

Instead, normalize at read time with a single helper that returns a uniform {field => [before, after]} for any event, deriving destroy's diff from the object snapshot. One tested place; stored data stays honest and minimal.

def timeline_changeset(version)
  case version.event
  when "destroy"
    version.object_deserialized.transform_values { |v| [v, nil] }
  else
    version.changeset # create & update already give [before, after]
  end
end

Decision 2 — actor (whodunnit) is read-time only, no schema change

whodunnit is native PaperTrail (the built-in column — t.string "whodunnit" in db/schema.rb — plus set_paper_trail_whodunnit / PaperTrail.request.whodunnit / version.whodunnit). It already holds the acting user's id, per row, so "changed by" is available straight from the versions table (distinct from subject_person_id, which is the subject).

  • No label snapshot. The only strong case for freezing an actor label was data loss on user deletion — but users with history won't be deleted, so that's moot. A snapshot would also go stale on name changes.
  • No new user_id column. whodunnit already carries the id.
  • Just batched-preload users at read time to kill the current N+1 (User.find_by per row in the partial):
ids   = versions.map(&:whodunnit).compact.map(&:to_i)
users = User.where(id: ids).index_by(&:id)
# per row: users[version.whodunnit.to_i]

Wart: whodunnit is a String, not a typed FK, so no includes(:user) and a .to_i cast is needed. Only if that ergonomics gets in the way, add a typed user_id meta later — a nicety, not a correctness need.

Scope

  • Decide where the normalizer lives (Version decorator / timeline PORO / helper)
  • Route the new person-timeline reader through it
  • Route the existing app/views/application/_papertrail_versions.html.erb partial through it (currently skips destroy diffs entirely: version.event != 'destroy' — should show "everything removed")
  • Replace the actor N+1 in that partial (User.find_by(id: version.whodunnit) per row) with a batched preload
  • Handle nil whodunnit (system / console / seed / rake / background-job actions) — display as "System"/"Unknown" and account for it in any actor filter
  • Spec create/update/destroy cases

Notes

  • Serialization is YAML (no PaperTrail initializer → defaults).
  • object_changes is auto-enabled because the object_changes column exists on versions.
Ngôn ngữ chính
Ruby
Star
15
Fork
28
Merge trung bình
1 ngày 12 phút
Pull request đã merge (30 ngày)
262

Chuẩn bị môi trường

Mở trong Codespaces

Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của rubyforgood/awbw

Tất cả issue của rubyforgood/awbw

Issue tương tự

Thêm issue về Ruby

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.