Add display author to public content forms#1557
Open
maebeale wants to merge 1 commit into
Open
Conversation
Content editors need to attribute public-facing stories, events, resources, and tutorials to a chosen author independently of who created the record, so the displayed byline can differ from the internal creator. - Add nullable author reference (User) to stories, events, resources, tutorials - Add created_by reference to tutorials so it can track its internal creator - Add a "Display author" select to each public form, defaulting to the existing author/creator or the current user - Switch Story search and author sort to use the new author association - Permit author_id params and update factories Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces a dedicated “Display author” for public-facing content (stories, events, resources, tutorials) so public attribution can differ from the internal creator (created_by). It adds new author associations, wires them into the admin forms/controllers, and updates story search/sorting to use the new association.
Changes:
- Added
authorreferences to stories/events/resources/tutorials and a newcreated_byreference for tutorials. - Added
belongs_to :author(and tutorial:created_by) associations and updated Story search/sort joins to useauthor. - Added “Display author” selects to the relevant forms and permitted
author_idin controllers (plus supporting factory updates).
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| spec/factories/tutorials.rb | Adds author/created_by associations to tutorial factory. |
| spec/factories/stories.rb | Adds author association to story factory. |
| spec/factories/resources.rb | Adds author association to resource factory. |
| spec/factories/events.rb | Adds author association to event factory. |
| db/migrate/20260308143000_add_author_to_public_forms.rb | Adds author_id refs to public models and created_by_id to tutorials. |
| app/views/tutorials/_form.html.erb | Adds display-author select and a created_by_id hidden field. |
| app/views/stories/_form.html.erb | Adds display-author select to story form. |
| app/views/resources/_form.html.erb | Adds display-author select to resource form. |
| app/views/events/_form.html.erb | Adds display-author select and adjusts “Created by” display placement. |
| app/models/tutorial.rb | Adds author and created_by associations. |
| app/models/story.rb | Adds author association and switches search join to author. |
| app/models/resource.rb | Adds author association (note: collides with existing author string column). |
| app/models/event.rb | Adds author association. |
| app/controllers/tutorials_controller.rb | Sets created_by on create, builds authors list, permits author_id/created_by_id. |
| app/controllers/stories_controller.rb | Includes author in index scope, builds authors list, sorts/permits author_id. |
| app/controllers/resources_controller.rb | Builds authors list using author_id and permits author_id. |
| app/controllers/events_controller.rb | Builds authors list and permits author_id. |
Comment on lines
+17
to
18
| belongs_to :author, class_name: "User", optional: true | ||
| belongs_to :created_by, class_name: "User" |
| @resource.gallery_assets.build | ||
| @windows_types = WindowsType.all | ||
| @authors = authorized_scope(User.has_access.or(User.where(id: @resource.created_by_id))) | ||
| @authors = authorized_scope(User.has_access.or(User.where(id: @resource.author_id))) |
Comment on lines
+415
to
+420
| <%= f.input :author_id, | ||
| as: :select, | ||
| label: "Display author", | ||
| collection: @authors, | ||
| selected: f.object.author_id || current_user&.id, | ||
| input_html: { class: "block w-full rounded-md border-gray-300 shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm" } %> |
Comment on lines
+265
to
+270
| <%= f.input :author_id, | ||
| as: :select, | ||
| label: "Display author", | ||
| collection: @authors, | ||
| selected: f.object.author_id || current_user&.id, | ||
| input_html: { class: "block w-full rounded-md border-gray-300 shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm" } %> |
Comment on lines
+33
to
+38
| <%= f.input :author_id, | ||
| as: :select, | ||
| label: "Display author", | ||
| collection: @authors, | ||
| selected: f.object.author_id || current_user&.id, | ||
| input_html: { class: "block w-full rounded-md border-gray-300 shadow-sm focus:ring-blue-500 focus:border-blue-500 sm:text-sm" } %> |
Comment on lines
124
to
128
| def tutorial_params | ||
| params.require(:tutorial).permit( | ||
| :title, :body, :rhino_body, :position, :youtube_url, | ||
| :author_id, :created_by_id, | ||
| :featured, :published, :publicly_visible, :publicly_featured, |
| @@ -1,4 +1,5 @@ | |||
| <%= simple_form_for(@tutorial, html: { multipart: true }) do |f| %> | |||
| <%= f.hidden_field :created_by_id, value: f.object.created_by_id || current_user&.id %> | |||
| .order(:created_at) | ||
| @people = Person.order(Arel.sql("LOWER(first_name), LOWER(last_name)")) | ||
| @users = User.has_access.includes(:person).left_joins(:person).order(Arel.sql("people.first_name IS NULL, LOWER(people.first_name), LOWER(people.last_name), LOWER(users.email)")) | ||
| @authors = authorized_scope(User.has_access.or(User.where(id: @story.author_id))) |
| .select { |type, _| type.nil? || (type.published? && !type.story_specific? && !type.profile_specific?) } | ||
| .sort_by { |type, _| type&.name.to_s.downcase } | ||
| @sectors = Sector.published.order(:name) | ||
| @authors = authorized_scope(User.has_access.or(User.where(id: @event.author_id))) |
| .select { |type, _| type.nil? || type.published? } | ||
| .sort_by { |type, _| type&.name.to_s.downcase } | ||
| @sectors = Sector.published.order(:name) | ||
| @authors = authorized_scope(User.has_access.or(User.where(id: @tutorial.author_id))) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What is the goal of this PR and why is this important?
created_by, so the public byline could not differ from the internal creator. This adds a dedicated "Display author" so editors control attribution directly.How did you approach the change?
authorreference (→users) tostories,events,resources, andtutorials, plus acreated_byreference totutorials(it previously had none).belongs_to :author, class_name: "User", optional: trueto each model.authorassociation instead ofcreated_by.author_id(andcreated_by_idwhere needed) in the controllers and updated factories.UI Testing Checklist
created_byset on createAnything else to add?
main; the PR diff is clean (only the author changes) since the base is a direct ancestor, but a rebase before merge may be worth it. Screenshots to be added for the four forms.