Person timeline: normalize PaperTrail changesets across create/update/destroy at read time
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
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ả
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_idcolumn.whodunnitalready carries the id. - Just batched-preload users at read time to kill the current N+1 (
User.find_byper 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.erbpartial 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_changesis auto-enabled because theobject_changescolumn exists onversions.
- 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
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.
- Có Dockerfile hoặc tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- 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.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của rubyforgood/awbw
-
blocked
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
rubyforgood/awbw#2824 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
rubyforgood/awbw#2822 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
rubyforgood/awbw#2160 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Update callout faq defualt text when the new person subscription launchesCó thể đã có người làm @maebeale đã nhận 80 ngày trước. Đang mởblocked
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
rubyforgood/awbw#2095 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
rubyforgood/awbw#2088 ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của rubyforgood/awbw
Issue tương tự
-
documentation
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 65/100
alphagov/tech-docs-gem#580 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Onboarding form: instructor radio never pre-selected "Yes" (permission vs permissions typo)Có thể đã có người làm @ThakuraAnki đã nhận hôm nay. Đang mởbug
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 72/100
WikiEducationFoundation/WikiEduDashboard#7235 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
Maintainer thường phản hồi trong vòng 1 ngày
-
enhancement priority: low
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
davidteren/mutineer#361 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 86/100
zerocracy/judges-action#3021 ·
Maintainer thường phản hồi trong vòng 2 ngày