Skip to content

JM: Standardize author crediting across creditable models#1940

Open
maebeale wants to merge 2 commits into
mainfrom
maebeale/author-field-audit
Open

JM: Standardize author crediting across creditable models#1940
maebeale wants to merge 2 commits into
mainfrom
maebeale/author-field-audit

Conversation

@maebeale

@maebeale maebeale commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

🤖 suggested review level: 5 Inspect 🔬 shared credit/search/sort concern touching 5 models + 3 idea models, a column rename, view/controller rewrites, and validation changes

Makes Workshop, Resource, Story, CommunityNews, and WorkshopVariation (and the *_idea models) credit, search, and sort by author identically, via AuthorCreditable.

Why

  • Workshop's list linked/printed raw full names, ignoring the credit preference — an "anonymous" author still leaked their name.
  • Workshop/WorkshopVariation linked to author profiles without the profile_is_searchable gate the others use.
  • Author search/sort coverage ranged from complete (Workshop) to none (WorkshopVariation), each implemented differently.

What

  • One display path: a shared credited_author_link helper renders every byline, linking to the author's profile only when the credit resolves to a searchable person (never for anonymous or legacy free-text credits).
  • author_credit precedence: explicit author → legacy free-text/user author → creating user's person → overridable missing_author_label (Workshop → "Facilitator").
  • Shared by_credited_person_name search + order_by_author sort on the concern; models declare legacy sources via legacy_author_name_columns / legacy_credited_user_columns. Retires the bespoke SQL in the Story/CommunityNews controllers and WorkshopSearchService. Adds author search+sort to Workshop and WorkshopVariation.
  • author_credit_preference defaults to full_name in the UI and is treated as full_name when blank — no data backfill; blank rows normalize on their next save.
  • Rename legacy community_news.user_author_idlegacy_author_user_id.
  • Coverage: shared model examples (credit/search/sort), plus helper, service, and request specs for the new behavior.

Deferred (needs a yes)

  • Renaming workshops.full_namelegacy_author_name: it's welded into a 14-column MySQL FULLTEXT index + the admin form, i.e. the risky "legacy migration" half. The concern folds it in under its current name, so search/sort/display already work. Quick follow-up once you confirm.

Copilot AI review requested due to automatic review settings July 5, 2026 02:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

# by `author_credit` and, on their next save, normalized by the callback below.
# There is no data backfill.
attribute :author_credit_preference, :string, default: "full_name"
before_validation :default_author_credit_preference

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 From Claude: Blank preference normalizes to full_name here on save, so legacy rows migrate lazily through normal use — no bulk backfill. Reads are covered by author_credit's default branch.

# anonymous, legacy free-text, or generic label that must not resolve to a
# profile. Mirrors author_credit's precedence so the linked person always
# matches the shown name.
def author_credit_person

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 From Claude: author_credit_person returns nil for anonymous and legacy free-text credits, so the byline helper never links those to a profile even when a person exists behind them.

# Explicit LEFT JOINs (as raw SQL strings with unique aliases) reaching every
# person that can be credited, so the aliases never collide with SearchCop's
# or Rails' own joins.
def credited_person_join_sql

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 From Claude: Explicit LEFT JOIN aliases (not Rails' positional people_users guesses) so this composes with SearchCop/other joins without alias collisions; callers OR it in via an id subquery.


# Orders by the credited author's name, matching `author_person` precedence:
# explicit author, then any legacy sources, then the creating user's person.
def order_by_author(direction)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 From Claude: Sorts by first name then last name to match the default displayed credit ("First Last"). CommunityNews previously sorted last-name-first; this unifies on the visible order.

def resolve_ids_order
return if sort.in?(%w[keywords popularity])

if sort == "author"

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 From Claude: order_by_author already applied the join-based ordering, so preserve it through the id round-trip and dedupe fan-out in Ruby (DISTINCT + ORDER BY on non-selected COALESCE columns would error in MySQL).

@maebeale maebeale changed the title Standardize author crediting across creditable models JM: Standardize author crediting across creditable models Jul 5, 2026
@maebeale

maebeale commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator Author

@jmilljr24 there were some nuances and discrepancies for the author data handling across the different models. this consolidates most of the api into the shared concern and tries to establish more conventions.

@jmilljr24

Copy link
Copy Markdown
Collaborator

@jmilljr24 there were some nuances and discrepancies for the author data handling across the different models. this consolidates most of the api into the shared concern and tries to establish more conventions.

Good idea. I know we've run into this a number of time

@maebeale maebeale requested a review from jmilljr24 July 7, 2026 12:51
maebeale and others added 2 commits July 7, 2026 10:14
Move author display, credited-name search, and author sort into
AuthorCreditable so Workshop/Resource/Story/CommunityNews/WorkshopVariation
(and the *_idea models) behave identically. Credit resolves through a single
precedence — explicit author person, legacy free-text/user author, creating
user's person, then an overridable missing_author_label (Workshop shows
"Facilitator"). Default author_credit_preference to full_name in the UI and
treat a blank preference as full_name in logic, with no data backfill. Rename
the legacy community_news author column to legacy_author_user_id.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Route every credited-author byline through a shared credited_author_link
helper that gates the profile link on profile_is_searchable and never links an
anonymous or legacy free-text credit (fixes the Workshop index leaking names
for anonymous authors and Workshop/WorkshopVariation linking non-searchable
profiles). Replace the bespoke author-sort SQL in the Story/CommunityNews
controllers and the WorkshopSearchService author filter with the shared
order_by_author / by_credited_person_name scopes, and add author search+sort to
Workshop and WorkshopVariation. Cover the new behavior in helper, service,
request, and shared model specs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@maebeale maebeale force-pushed the maebeale/author-field-audit branch from 7990756 to 78b4b0e Compare July 7, 2026 14:17
Copilot AI review requested due to automatic review settings July 7, 2026 14:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@maebeale maebeale marked this pull request as ready for review July 7, 2026 14:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants