diff --git a/app/controllers/stories_controller.rb b/app/controllers/stories_controller.rb index 96b30072d..95c320c72 100644 --- a/app/controllers/stories_controller.rb +++ b/app/controllers/stories_controller.rb @@ -9,7 +9,7 @@ def index if turbo_frame_request? per_page = params[:number_of_items_per_page].presence || 12 base_scope = authorized_scope(Story.includes(:windows_type, :organization, :workshop, - :created_by, :bookmarks, :primary_asset, + :author, :created_by, :bookmarks, :primary_asset, :story_idea)) filtered = base_scope.search_by_params(params) sortable = %w[title updated_at created_at windows_type workshop author organization] @@ -62,6 +62,7 @@ def edit def create @story = Story.new(story_params.except(:category_ids, :sector_ids)) + @story.created_by = current_user authorize! @story success = false @@ -127,11 +128,7 @@ def set_form_variables @story_idea = StoryIdea.find(params[:story_idea_id]) if params[:story_idea_id].present? @user = User.find(params[:user_id]) if params[:user_id].present? @organizations = authorized_scope(Organization.all, as: :affiliated).order(:name) - @story_ideas = authorized_scope(StoryIdea.includes(:created_by)) - .references(:users) - .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)")) @windows_types = WindowsType.all @workshops = authorized_scope(Workshop.all).includes(:windows_type).order(:title) @categories_grouped = @@ -174,7 +171,7 @@ def apply_sort(scope, column, direction) scope.left_joins(:workshop) .reorder(Workshop.arel_table[:title].public_send(dir)) when "author" - scope.left_joins(created_by: :person) + scope.left_joins(:author) .reorder(Person.arel_table[:first_name].public_send(dir)) when "organization" scope.left_joins(:organization) @@ -189,7 +186,7 @@ def story_params params.require(:story).permit( :title, :rhino_body, :featured, :published, :publicly_visible, :publicly_featured, :youtube_url, :website_url, :windows_type_id, :organization_id, :workshop_id, :external_workshop_title, - :created_by_id, :updated_by_id, :story_idea_id, :spotlighted_facilitator_id, :author_credit_preference, + :author_id, :updated_by_id, :story_idea_id, :spotlighted_facilitator_id, :author_credit_preference, category_ids: [], sector_ids: [], primary_asset_attributes: [ :id, :file, :_destroy ], @@ -206,6 +203,7 @@ def set_story_attributes_from(idea) external_workshop_title: idea.external_workshop_title, windows_type_id: idea.windows_type_id, youtube_url: idea.youtube_url, + author_id: idea.author_id, author_credit_preference: idea.author_credit_preference } end diff --git a/app/controllers/story_ideas_controller.rb b/app/controllers/story_ideas_controller.rb index fae4b9508..973bbe21e 100644 --- a/app/controllers/story_ideas_controller.rb +++ b/app/controllers/story_ideas_controller.rb @@ -39,6 +39,7 @@ def create @story_idea = StoryIdea.new(story_idea_params.except(:category_ids, :sector_ids)) @story_idea.created_by = current_user @story_idea.updated_by = current_user + @story_idea.author = current_user.person authorize! @story_idea success = false diff --git a/app/helpers/person_helper.rb b/app/helpers/person_helper.rb index 74b6f124a..95683ced4 100644 --- a/app/helpers/person_helper.rb +++ b/app/helpers/person_helper.rb @@ -1,4 +1,14 @@ module PersonHelper + # Builds [ label, id ] pairs for a person select. Shows just the name, adding + # the email only to disambiguate people who share a full name. + def person_select_options(people) + duplicate_names = people.map(&:full_name).tally.select { |_, count| count > 1 }.keys.to_set + people.map do |person| + label = duplicate_names.include?(person.full_name) ? person.full_name_with_email : person.full_name + [ label, person.id ] + end + end + def person_profile_button(person, truncate_at: nil, subtitle: nil, display_name: nil, data: {}, inactive: false) if inactive bg = "bg-gray-100" diff --git a/app/models/concerns/author_creditable.rb b/app/models/concerns/author_creditable.rb index a702382be..5618aa946 100644 --- a/app/models/concerns/author_creditable.rb +++ b/app/models/concerns/author_creditable.rb @@ -20,7 +20,7 @@ module AuthorCreditable }.freeze def author_credit - person = created_by&.person + person = credited_person case author_credit_preference when "full_name" then person&.full_name || "Anonymous" when "first_name_last_initial" @@ -33,4 +33,10 @@ def author_credit else person&.name || "Anonymous" end end + + # The person credited as the author. Models with a direct author association + # (Story, StoryIdea) override this; the rest derive it from the creating user. + def credited_person + created_by&.person + end end diff --git a/app/models/story.rb b/app/models/story.rb index 7c479dc68..46e95f358 100644 --- a/app/models/story.rb +++ b/app/models/story.rb @@ -4,6 +4,7 @@ class Story < ApplicationRecord has_rich_text :rhino_body + belongs_to :author, class_name: "Person", optional: true belongs_to :created_by, class_name: "User" belongs_to :updated_by, class_name: "User" belongs_to :windows_type @@ -36,6 +37,10 @@ class Story < ApplicationRecord validates :title, presence: true, uniqueness: true validates :rhino_body, presence: true + # Default the credit preference from the author's own name display preference, + # while leaving it overridable per story. + before_validation :default_author_credit_preference + # Nested attributes accepts_nested_attributes_for :primary_asset, allow_destroy: true, reject_if: :all_blank accepts_nested_attributes_for :gallery_assets, allow_destroy: true, reject_if: :all_blank @@ -48,7 +53,7 @@ class Story < ApplicationRecord attributes person_first: "people.first_name", person_last: "people.last_name" options :all, type: :text, default: true, default_operator: :or - scope { join_rich_texts.left_joins(created_by: :person) } + scope { join_rich_texts.left_joins(:author) } attributes action_text_body: "action_text_rich_texts.plain_text_body" options :action_text_body, type: :text, default: true, default_operator: :or end @@ -85,10 +90,18 @@ def self.search_by_params(params) stories end + def credited_person + author + end + def name title end + def default_author_credit_preference + self.author_credit_preference ||= author&.display_name_preference + end + def organization_name organization&.name end diff --git a/app/models/story_idea.rb b/app/models/story_idea.rb index 65155be0b..53d7702ee 100644 --- a/app/models/story_idea.rb +++ b/app/models/story_idea.rb @@ -14,6 +14,7 @@ def self.search_by_params(params) has_rich_text :rhino_body + belongs_to :author, class_name: "Person", optional: true belongs_to :created_by, class_name: "User" belongs_to :updated_by, class_name: "User" belongs_to :organization @@ -48,6 +49,10 @@ def self.search_by_params(params) accepts_nested_attributes_for :primary_asset, allow_destroy: true, reject_if: :all_blank accepts_nested_attributes_for :gallery_assets, allow_destroy: true, reject_if: :all_blank + def credited_person + author + end + def name "StoryIdea ##{id}" end diff --git a/app/views/stories/_form.html.erb b/app/views/stories/_form.html.erb index 15fd78dd5..d4ee32998 100644 --- a/app/views/stories/_form.html.erb +++ b/app/views/stories/_form.html.erb @@ -205,21 +205,6 @@ <%= render "shared/form_image_fields", f: f, include_primary_asset: true %>
-
- <%= f.input :author_credit_preference, - as: :select, - collection: AuthorCreditable::ADMIN_FORM_OPTIONS, - prompt: "Select a preference", - selected: f.object.author_credit_preference || story_idea&.author_credit_preference, - label: "Author credit preference", - hint: "Controls how the author's name is displayed", - input_html: { - class: select_caret_class(blank: f.object.author_credit_preference.blank?), - style: custom_caret_style, - onchange: select_caret_onchange - } %> -
-
<%= f.input :youtube_url, as: :text, label: "YouTube URL", @@ -233,97 +218,74 @@ hint: "(open in external website instead)", input_html: { rows: 1, class: "w-full" } %>
-
- <% if story_idea %> -
-
- Story idea author credit: -
- <% if story_idea.created_by.person %> - <%= person_profile_button(story_idea.created_by.person, display_name: story_idea.author_credit, subtitle: story_idea.created_by.person.full_name) %> - <% else %> - <%= story_idea.author_credit %> - <% end %> -
- Story idea "author credit preference": -
-
<%= link_to story_idea.author_credit_preference, edit_story_idea_path(story_idea, anchor: "publish-preferences"), class: "hover:underline hover:text-blue-600" %>
-
- - <% if f.object.persisted? %> -
- Last updated by: -
- <%= f.object.updated_by&.full_name %> -
- <%= f.object.updated_at.in_time_zone.strftime("%Y-%m-%d %I:%M %P") %> -
- <% end %> -
- <% elsif f.object.persisted? %> -
- Last updated by: -
- <%= f.object.updated_by&.full_name %> -
- <%= f.object.updated_at.in_time_zone.strftime("%Y-%m-%d %I:%M %P") %> -
- <% end %> - -
- <%= f.input :created_by_id, - collection: @users.map { |u| [ u.full_name_with_email, u.id ] }, - prompt: "Select an author", - label: (f.object.created_by&.person ? ( - link_to "Story author", - person_path(f.object.created_by.person), - class: "hover:underline") : "Story author").html_safe, + <%= f.input :spotlighted_facilitator_id, + collection: person_select_options(@people), + prompt: "Select a facilitator", + label: (f.object.spotlighted_facilitator_id ? (link_to "Story spotlighted facilitator", + person_path(f.object.spotlighted_facilitator_id), + class: "hover:underline") : "Story spotlighted facilitator").html_safe, label_html: { class: "block font-medium mb-1 text-gray-700" }, input_html: { - class: select_caret_class(blank: f.object.created_by_id.blank?), + class: select_caret_class(blank: f.object.spotlighted_facilitator_id.blank?), style: custom_caret_style, onchange: select_caret_onchange } %>
+
+
- <%= f.input :spotlighted_facilitator_id, - collection: @people.map { |p| [ p.full_name_with_email, p.id ] }, - prompt: "Select a facilitator", - label: (f.object.spotlighted_facilitator_id ? (link_to "Story spotlighted facilitator", - person_path(f.object.spotlighted_facilitator_id), - class: "hover:underline") : "Story spotlighted facilitator").html_safe, + <%= f.input :author_id, + collection: person_select_options(@people), + prompt: "Select an author", + label: (f.object.author ? ( + link_to "Story author", + person_path(f.object.author), + class: "hover:underline") : "Story author").html_safe, label_html: { class: "block font-medium mb-1 text-gray-700" }, input_html: { - class: select_caret_class(blank: f.object.spotlighted_facilitator_id.blank?), + class: select_caret_class(blank: f.object.author_id.blank?), style: custom_caret_style, onchange: select_caret_onchange } %>
- <% story_idea_label = if f.object.story_idea - (link_to "Source story idea", - story_idea_path(f.object.story_idea), class: "hover:underline") - else - "Source story idea" - end %> - <%= f.input :story_idea_id, - collection: @story_ideas, label_method: :full_name, - value_method: :id, - selected: f.object.story_idea_id || @story_idea&.id, - label: story_idea_label.html_safe, - prompt: "Select idea", + <%= f.input :author_credit_preference, + as: :select, + collection: AuthorCreditable::ADMIN_FORM_OPTIONS, + prompt: "Select a preference", + selected: f.object.author_credit_preference || story_idea&.author_credit_preference || f.object.author&.display_name_preference, + label: "Author credit preference", + hint: "Defaults to the author's name display preference; controls how their name is shown", input_html: { - class: select_caret_class(blank: f.object.story_idea_id.blank?), + class: select_caret_class(blank: f.object.author_credit_preference.blank?), style: custom_caret_style, onchange: select_caret_onchange } %>
+ <% if story_idea %> +
+ From + <%= link_to "Story Idea # #{story_idea.id}", story_idea_path(story_idea), class: "font-medium text-gray-700 underline" %> + by + <% if story_idea.author %> + <%= link_to story_idea.author_credit, person_path(story_idea.author), class: "font-medium text-gray-800 underline" %> + <% else %> + <%= story_idea.author_credit %> + <% end %> + (preference "<%= link_to AuthorCreditable::ADMIN_FORM_OPTIONS.key(story_idea.author_credit_preference) || story_idea.author_credit_preference&.humanize, + edit_story_idea_path(story_idea, anchor: "publish-preferences"), + class: "italic underline hover:text-blue-600" %>") +
+ <% end %> + + <%= f.hidden_field :story_idea_id, value: f.object.story_idea_id || @story_idea&.id %> + <% if remaining_categories.any? %>
diff --git a/app/views/stories/_story_results.html.erb b/app/views/stories/_story_results.html.erb index 0a72f05b4..85419b665 100644 --- a/app/views/stories/_story_results.html.erb +++ b/app/views/stories/_story_results.html.erb @@ -62,7 +62,7 @@ <%= story.workshop&.title&.truncate(30) %> - <%= story.created_by.name %> + <%= story.author&.full_name || "—" %> <%= story.organization&.name&.truncate(30) %> diff --git a/app/views/stories/show.html.erb b/app/views/stories/show.html.erb index c2f3f28ee..460fb6da1 100644 --- a/app/views/stories/show.html.erb +++ b/app/views/stories/show.html.erb @@ -28,8 +28,8 @@

Story by: - <% if @story.created_by.person&.profile_is_searchable %> - <%= link_to @story.author_credit, person_path(@story.created_by) %> + <% if @story.author&.profile_is_searchable %> + <%= link_to @story.author_credit, person_path(@story.author) %> <% else %> <%= @story.author_credit %> <% end %> diff --git a/app/views/story_ideas/show.html.erb b/app/views/story_ideas/show.html.erb index c54ef8a99..fc5701c37 100644 --- a/app/views/story_ideas/show.html.erb +++ b/app/views/story_ideas/show.html.erb @@ -31,13 +31,13 @@

Story by: - <% if @story_idea.created_by&.person && allowed_to?(:show?, @story_idea.created_by.person) %> - <%= link_to @story_idea.created_by.name, - person_path(@story_idea.created_by.person), + <% if @story_idea.author && allowed_to?(:show?, @story_idea.author) %> + <%= link_to @story_idea.author.full_name, + person_path(@story_idea.author), data: { turbo_frame: "_top" }, class: "inline-block px-3 py-1 rounded-md text-sm font-medium #{DomainTheme.bg_class_for(:people, intensity: 100)} #{DomainTheme.text_class_for(:people)} #{DomainTheme.bg_class_for(:people, intensity: 100, hover: true)}" %> <% else %> - <%= @story_idea.created_by&.name || "—" %> + <%= @story_idea.author&.full_name || "—" %> <% end %>
diff --git a/db/migrate/20260605120000_add_author_to_stories_and_story_ideas.rb b/db/migrate/20260605120000_add_author_to_stories_and_story_ideas.rb new file mode 100644 index 000000000..33d5a67b9 --- /dev/null +++ b/db/migrate/20260605120000_add_author_to_stories_and_story_ideas.rb @@ -0,0 +1,32 @@ +class AddAuthorToStoriesAndStoryIdeas < ActiveRecord::Migration[7.2] + def up + add_reference :stories, :author, type: :bigint, null: true, index: true + add_reference :story_ideas, :author, type: :bigint, null: true, index: true + + add_foreign_key :stories, :people, column: "author_id" + add_foreign_key :story_ideas, :people, column: "author_id" + + # Backfill author from the creating user's linked person, preserving existing + # author credits. Rows whose creator has no linked person stay null (Anonymous). + execute <<~SQL.squish + UPDATE stories + JOIN users ON users.id = stories.created_by_id + SET stories.author_id = users.person_id + WHERE users.person_id IS NOT NULL + SQL + + execute <<~SQL.squish + UPDATE story_ideas + JOIN users ON users.id = story_ideas.created_by_id + SET story_ideas.author_id = users.person_id + WHERE users.person_id IS NOT NULL + SQL + end + + def down + remove_foreign_key :stories, column: "author_id" if foreign_key_exists?(:stories, column: "author_id") + remove_foreign_key :story_ideas, column: "author_id" if foreign_key_exists?(:story_ideas, column: "author_id") + remove_reference :stories, :author, if_exists: true + remove_reference :story_ideas, :author, if_exists: true + end +end diff --git a/db/schema.rb b/db/schema.rb index e0f387ba6..2c5765eab 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.1].define(version: 2026_05_29_155200) do +ActiveRecord::Schema[8.1].define(version: 2026_06_05_120000) do create_table "action_text_mentions", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.bigint "action_text_rich_text_id", null: false t.datetime "created_at", null: false @@ -18,7 +18,6 @@ t.string "mentionable_type", null: false t.datetime "updated_at", null: false t.index ["action_text_rich_text_id", "mentionable_type", "mentionable_id"], name: "index_at_mentions_on_rich_text_and_mentionable", unique: true - t.index ["action_text_rich_text_id"], name: "index_action_text_mentions_on_action_text_rich_text_id" t.index ["mentionable_type", "mentionable_id"], name: "index_action_text_mentions_on_mentionable" end @@ -899,6 +898,7 @@ create_table "stories", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.string "author_credit_preference" + t.bigint "author_id" t.text "body" t.datetime "created_at", null: false t.integer "created_by_id", null: false @@ -918,6 +918,7 @@ t.integer "windows_type_id", null: false t.integer "workshop_id" t.string "youtube_url" + t.index ["author_id"], name: "index_stories_on_author_id" t.index ["created_by_id"], name: "index_stories_on_created_by_id" t.index ["organization_id"], name: "index_stories_on_organization_id" t.index ["published"], name: "index_stories_on_published" @@ -930,6 +931,7 @@ create_table "story_ideas", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.string "author_credit_preference" + t.bigint "author_id" t.text "body" t.datetime "created_at", null: false t.integer "created_by_id", null: false @@ -942,6 +944,7 @@ t.integer "windows_type_id", null: false t.integer "workshop_id" t.string "youtube_url" + t.index ["author_id"], name: "index_story_ideas_on_author_id" t.index ["created_by_id"], name: "index_story_ideas_on_created_by_id" t.index ["organization_id"], name: "index_story_ideas_on_organization_id" t.index ["updated_by_id"], name: "index_story_ideas_on_updated_by_id" @@ -1333,8 +1336,6 @@ t.index ["year", "month"], name: "index_workshops_on_year_and_month" end - add_foreign_key "action_text_mentions", "action_text_rich_texts" - add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" add_foreign_key "affiliations", "organizations" add_foreign_key "affiliations", "organizations", column: "organization_agency_id" @@ -1403,6 +1404,7 @@ add_foreign_key "resources", "workshops" add_foreign_key "sectorable_items", "sectors" add_foreign_key "stories", "organizations" + add_foreign_key "stories", "people", column: "author_id" add_foreign_key "stories", "people", column: "spotlighted_facilitator_id" add_foreign_key "stories", "story_ideas" add_foreign_key "stories", "users", column: "created_by_id" @@ -1410,6 +1412,7 @@ add_foreign_key "stories", "windows_types" add_foreign_key "stories", "workshops" add_foreign_key "story_ideas", "organizations" + add_foreign_key "story_ideas", "people", column: "author_id" add_foreign_key "story_ideas", "users", column: "created_by_id" add_foreign_key "story_ideas", "users", column: "updated_by_id" add_foreign_key "story_ideas", "windows_types" diff --git a/spec/factories/stories.rb b/spec/factories/stories.rb index c2e0848bf..af1755af0 100644 --- a/spec/factories/stories.rb +++ b/spec/factories/stories.rb @@ -3,6 +3,7 @@ association :windows_type association :organization association :workshop + association :author, factory: :person association :created_by, factory: :user association :updated_by, factory: :user sequence(:title) { |n| "Story #{n}" } diff --git a/spec/factories/story_ideas.rb b/spec/factories/story_ideas.rb index 4d411b6c3..9adbc0cd2 100644 --- a/spec/factories/story_ideas.rb +++ b/spec/factories/story_ideas.rb @@ -7,6 +7,7 @@ rhino_body { "

My Body

" } permission_given { true } author_credit_preference { "full_name" } + association :author, factory: :person association :created_by, factory: :user association :updated_by, factory: :user diff --git a/spec/helpers/person_helper_spec.rb b/spec/helpers/person_helper_spec.rb new file mode 100644 index 000000000..dfc585144 --- /dev/null +++ b/spec/helpers/person_helper_spec.rb @@ -0,0 +1,29 @@ +require "rails_helper" + +RSpec.describe PersonHelper, type: :helper do + describe "#person_select_options" do + it "shows only the name when the full name is unique" do + amy = create(:person, first_name: "Amy", last_name: "User", email: "amy@example.com") + ben = create(:person, first_name: "Ben", last_name: "Smith", email: "ben@example.com") + + options = helper.person_select_options([ amy, ben ]) + + expect(options).to contain_exactly([ "Amy User", amy.id ], [ "Ben Smith", ben.id ]) + end + + it "appends the email only for people who share a full name" do + amy_one = create(:person, first_name: "Amy", last_name: "User", email: "amy.one@example.com") + amy_two = create(:person, first_name: "Amy", last_name: "User", email: "amy.two@example.com") + ben = create(:person, first_name: "Ben", last_name: "Smith", email: "ben@example.com") + + options = helper.person_select_options([ amy_one, amy_two, ben ]) + + expect(options).to contain_exactly( + [ amy_one.full_name_with_email, amy_one.id ], + [ amy_two.full_name_with_email, amy_two.id ], + [ "Ben Smith", ben.id ] + ) + expect(amy_one.full_name_with_email).to include("(") + end + end +end diff --git a/spec/models/story_spec.rb b/spec/models/story_spec.rb index 36e94234e..a4b4453a1 100644 --- a/spec/models/story_spec.rb +++ b/spec/models/story_spec.rb @@ -3,6 +3,25 @@ RSpec.describe Story, type: :model do it_behaves_like "author_creditable", factory: :story + describe "author credit preference default" do + it "defaults a blank preference from the author's display name preference" do + author = create(:person, display_name_preference: "first_name_only") + story = create(:story, author: author, author_credit_preference: nil) + expect(story.author_credit_preference).to eq("first_name_only") + end + + it "does not override an explicitly set preference" do + author = create(:person, display_name_preference: "first_name_only") + story = create(:story, author: author, author_credit_preference: "anonymous") + expect(story.author_credit_preference).to eq("anonymous") + end + + it "leaves the preference blank when there is no author" do + story = create(:story, author: nil, author_credit_preference: nil) + expect(story.author_credit_preference).to be_nil + end + end + describe "#attach_assets_from_idea!" do let(:idea) { create(:story_idea) } let(:story) { create(:story, story_idea: idea) } diff --git a/spec/requests/stories_spec.rb b/spec/requests/stories_spec.rb index 2fbc28c11..e6c2e6251 100644 --- a/spec/requests/stories_spec.rb +++ b/spec/requests/stories_spec.rb @@ -124,6 +124,7 @@ windows_type: wt_adult, workshop: ws_art, organization: org_alpha, + author: author_alice.person, created_by: author_alice).tap do |s| s.update_columns(created_at: 3.days.ago, updated_at: 1.day.ago) end @@ -135,6 +136,7 @@ windows_type: wt_children, workshop: ws_music, organization: org_zulu, + author: author_zara.person, created_by: author_zara).tap do |s| s.update_columns(created_at: 1.day.ago, updated_at: 3.days.ago) end diff --git a/spec/support/shared_examples/author_creditable.rb b/spec/support/shared_examples/author_creditable.rb index 3ac1b03f8..7bcb0966a 100644 --- a/spec/support/shared_examples/author_creditable.rb +++ b/spec/support/shared_examples/author_creditable.rb @@ -1,8 +1,16 @@ RSpec.shared_examples "author_creditable" do |factory:| describe "#author_credit" do - let(:author_user) { create(:user, :with_person) } - let(:person) { author_user.person } - let(:record) { create(factory, created_by: author_user) } + let(:person) { create(:person) } + # Story/StoryIdea credit a direct author association; other includers derive + # the credited person from the creating user. + let(:has_author_association) { described_class.reflect_on_association(:author).present? } + let(:record) do + if has_author_association + create(factory, author: person) + else + create(factory, created_by: create(:user, person: person)) + end + end context "when author_credit_preference is full_name" do it "returns the person's full name" do @@ -46,10 +54,13 @@ end end - context "when user has no person" do + context "when there is no credited person" do it "returns Anonymous" do - user_without_person = create(:user, person: nil) - record.update!(created_by: user_without_person) + if has_author_association + record.update!(author: nil) + else + record.update!(created_by: create(:user, person: nil)) + end expect(record.author_credit).to eq("Anonymous") end end