Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

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

オープン
#2,250 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
55/100
issue の種類
機能追加
明瞭さ
おおむね明確
活発さ
静か
技術スタック
ruby
領域
backend

調査の方向性

app/views/application/_papertrail_versions.html.erb と既存の person-timeline reader から始め、PaperTrail のバージョンがどのように読み込まれ、render されるかを追跡します。共有 normalizer をどこに置くべきかを決め、両方の reader でそれを経由するようにし、nil の actor を処理しながら whodunnit ユーザーを一括ロードし、create、update、destroy イベントをカバーする specs を追加します。

索引モデルが issue の本文から書いたものです。

説明

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.
主要言語
Ruby
スター
15
フォーク
28
平均マージ
1日 12分
マージ済み PR(30日)
262

環境構築

Codespaces で開く

このプロジェクトの開発コンテナを、あなたの GitHub アカウントでブラウザ上に起動します。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

rubyforgood/awbw のほかの issue

rubyforgood/awbw の issue をすべて見る

似ている issue

Ruby の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。