-
Affiliations
- <% active_affiliations = @organization.affiliations
- .select { |a| !a.inactive? && (a.end_date.nil? || a.end_date >= Date.current) && a.person.present? }
- .sort_by { |a| [a.person.first_name.to_s.downcase, a.person.last_name.to_s.downcase] } %>
- <% grouped = active_affiliations.group_by(&:person) %>
+
Facilitators
+ <% grouped = org_decorated.active_affiliations_by_facilitator.select { |person, _| allowed_to?(:show?, person) } %>
<% if grouped.any? %>
<% grouped.each do |person, person_affiliations| %>
-
+
<% titles = person_affiliations.filter_map { |a| a.title.presence }.uniq %>
<% titles = titles.sort_by { |t| [t.downcase.include?("facilitator") ? 0 : 1, t.downcase] } %>
<%= person_profile_button(person, subtitle: titles.any? ? titles.join(", ") : nil) %>
+ <% if current_user&.super_user? && !person.published? %>
+
+
+
+ <% end %>
<% end %>
<% else %>
-
No active affiliations.
+
No active facilitators.
<% end %>
diff --git a/db/seeds/features/2026-10-22-org-pages-list-active-facilitators.yml b/db/seeds/features/2026-10-22-org-pages-list-active-facilitators.yml
new file mode 100644
index 0000000000..892b94d15c
--- /dev/null
+++ b/db/seeds/features/2026-10-22-org-pages-list-active-facilitators.yml
@@ -0,0 +1,12 @@
+name: "Organization pages list active facilitators"
+area: people
+display_status: user_facing
+released_on: 2026-10-22
+pr_number: 2785
+summary: >-
+ An organization page now lists its active facilitators, and facilitators see only the ones whose
+ profiles they can open, so every name leads to a profile.
+pro_tips:
+ - "A facilitator's card still shows their other titles at the organization, like Director."
+ - "Admins see every active facilitator; a lock marks the ones hidden from facilitators, who don't see those cards."
+ - "On My bookmarks, a creator whose profile you can't open shows as a plain name."
diff --git a/spec/decorators/organization_decorator_spec.rb b/spec/decorators/organization_decorator_spec.rb
index 47911c9074..70e72ffe18 100644
--- a/spec/decorators/organization_decorator_spec.rb
+++ b/spec/decorators/organization_decorator_spec.rb
@@ -1,6 +1,26 @@
require "rails_helper"
RSpec.describe OrganizationDecorator do
+ describe "#active_affiliations_by_facilitator" do
+ let(:organization) { create(:organization) }
+ let(:facilitator) { create(:person, first_name: "Zoe") }
+ let(:earlier) { create(:person, first_name: "Abe") }
+
+ it "groups each active facilitator's active titles, sorted by name, leaving out everyone else" do
+ facilitation = create(:affiliation, organization: organization, person: facilitator)
+ director = create(:affiliation, organization: organization, person: facilitator, title: "Director")
+ create(:affiliation, organization: organization, person: facilitator, title: "Counselor", end_date: 1.month.ago)
+ create(:affiliation, organization: organization, person: earlier)
+ create(:affiliation, organization: organization, title: "Board Member")
+ create(:affiliation, organization: organization, end_date: 1.month.ago)
+
+ grouped = organization.reload.decorate.active_affiliations_by_facilitator
+
+ expect(grouped.keys).to eq([ earlier, facilitator ])
+ expect(grouped[facilitator]).to contain_exactly(facilitation, director)
+ end
+ end
+
describe "#affiliated_since_display" do
let(:organization) { create(:organization) }
diff --git a/spec/requests/bookmarks_spec.rb b/spec/requests/bookmarks_spec.rb
index 8630d2fdfc..b740debfe8 100644
--- a/spec/requests/bookmarks_spec.rb
+++ b/spec/requests/bookmarks_spec.rb
@@ -129,6 +129,27 @@
expect(response).to have_http_status(:ok)
end
+ context "with the bookmarked item's creator" do
+ let(:creator) { create(:user, person: create(:person, first_name: "Cara", last_name: "Creator")) }
+
+ before { workshop.update_columns(created_by_id: creator.id) }
+
+ it "links the creator's profile when the viewer can open it" do
+ create(:affiliation, person: creator.person)
+
+ get personal_bookmarks_path, headers: { "Turbo-Frame" => "personal_bookmarks_results" }
+
+ expect(response.body).to include(person_path(creator.person))
+ end
+
+ it "shows the creator's name without a link when the viewer can't open the profile" do
+ get personal_bookmarks_path, headers: { "Turbo-Frame" => "personal_bookmarks_results" }
+
+ expect(response.body).not_to include(person_path(creator.person))
+ expect(response.body).to include("Cara")
+ end
+ end
+
it "can filter personal bookmarks by keyword via turbo frame" do
get personal_bookmarks_path, params: { keyword: workshop.title },
headers: { "Turbo-Frame" => "personal_bookmarks_results" }
diff --git a/spec/views/organizations/show.html.erb_spec.rb b/spec/views/organizations/show.html.erb_spec.rb
index 28838201c9..23cc302aee 100644
--- a/spec/views/organizations/show.html.erb_spec.rb
+++ b/spec/views/organizations/show.html.erb_spec.rb
@@ -8,6 +8,7 @@
before do
assign(:organization, organization)
+ sign_in user
allow(view).to receive(:current_user).and_return(user)
render
end
@@ -40,4 +41,43 @@
expect(rendered).to match(/Facilitator.*Director/)
end
end
+
+ context "with people a viewer can't open" do
+ let(:facilitator) { create(:person, first_name: "Fay", last_name: "Active") }
+ let(:director) { create(:person, first_name: "Dee", last_name: "Director") }
+ let(:lapsed) { create(:person, first_name: "Lee", last_name: "Lapsed") }
+ let(:hidden) { create(:person, first_name: "Hal", last_name: "Hidden", profile_is_searchable: false) }
+
+ before do
+ create(:affiliation, person: facilitator, organization: organization)
+ create(:affiliation, person: director, organization: organization, title: "Director")
+ create(:affiliation, person: lapsed, organization: organization, end_date: 1.month.ago)
+ create(:affiliation, person: hidden, organization: organization)
+ assign(:organization, organization.reload)
+ render
+ end
+
+ it "lists only active facilitators whose profile the viewer can open" do
+ expect(rendered).not_to include("profile-hidden-lock")
+ expect(rendered).to include(person_path(facilitator))
+ expect(rendered).not_to include(person_path(director))
+ expect(rendered).not_to include(person_path(lapsed))
+ expect(rendered).not_to include(person_path(hidden))
+ end
+
+ context "when the viewer is an admin" do
+ let(:user) { admin }
+
+ it "lists every active facilitator, but not other titles" do
+ expect(rendered).to include(person_path(facilitator))
+ expect(rendered).to include(person_path(hidden))
+ expect(rendered).not_to include(person_path(director))
+ expect(rendered).not_to include(person_path(lapsed))
+ end
+
+ it "locks only the facilitators others can't open" do
+ expect(rendered.scan('data-testid="profile-hidden-lock"').count).to eq(1)
+ end
+ end
+ end
end