From cd830d23cdc9566e37e7bfc7618c388aabe21a60 Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Wed, 8 Apr 2026 06:40:35 +0000
Subject: [PATCH 01/32] AO3-7144 Update Collections index page header
---
app/views/collections/index.html.erb | 20 ++++++++------------
config/locales/views/en.yml | 8 ++++----
2 files changed, 12 insertions(+), 16 deletions(-)
diff --git a/app/views/collections/index.html.erb b/app/views/collections/index.html.erb
index f3329008b9a..448d87d0ee9 100755
--- a/app/views/collections/index.html.erb
+++ b/app/views/collections/index.html.erb
@@ -1,23 +1,19 @@
- <% if @user %>
- <%= t(".page_heading.users_collections", user: @user.login) %>
+ <% if @collections.empty? %>
+ <%# do we need this disclaimer? %>
+ <%= ts("Sorry, there were no collections found.") %>
+ <% elsif @user %>
+ <%= t(".page_heading.collections_by", collections: search_header(@collections, @query, ts("Collection")), user: @user.login) %>
<% elsif @collection %>
- <%= t(".page_heading.challenges_subcollections_in", collection: @collection.title) %>
+ <%= t(".page_heading.subcollections_in", subcollections: search_header(@collections, @query, ts("Subcollection")), collection: @collection.title) %>
<% elsif @work %>
- <%= t(".page_heading.collections_including", work: @work.title) %>
+ <%= t(".page_heading.collections_including", collections: search_header(@collections, @query, ts("Collection")), work: @work.title) %>
<% else %>
- <%= t(".page_heading.collections_in_the", archive: ArchiveConfig.APP_NAME) %>
+ <%= t(".page_heading.collections_in_the", collections: search_header(@collections, @query, ts("Collection")), archive: ArchiveConfig.APP_NAME) %>
<% end %>
-
- <% if @collections.empty? %>
- <%= ts("Sorry, there were no collections found.") %>
- <% else %>
- <%= search_header @collections, @query, ts("Collection") %>
- <% end %>
-
diff --git a/config/locales/views/en.yml b/config/locales/views/en.yml
index c2e3a15cd7a..55bd4c8a751 100644
--- a/config/locales/views/en.yml
+++ b/config/locales/views/en.yml
@@ -803,10 +803,10 @@ en:
label: Multifandom
index:
page_heading:
- challenges_subcollections_in: Challenges/Subcollections in %{collection}
- collections_in_the: Collections in the %{archive}
- collections_including: Collections including %{work}
- users_collections: "%{user}'s Collections"
+ collections_by: "%{collections} by %{user}"
+ collections_in_the: "%{collections} in the %{archive}"
+ collections_including: "%{collections} including %{work}"
+ subcollections_in: "%{subcollections} in %{collection}"
sidebar:
bookmarks: Bookmarked Items (%{count})
challenge_settings: Challenge Settings
From c7d5cce90652935c314e5d060262921d464695c6 Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Wed, 8 Apr 2026 22:45:04 +0000
Subject: [PATCH 02/32] AO3-7147 Add path for collection listings in a tag
---
app/helpers/search_helper.rb | 9 +++++++++
app/views/bookmarks/index.html.erb | 1 +
app/views/collections/index.html.erb | 8 ++++----
app/views/tags/show.html.erb | 1 +
app/views/works/index.html.erb | 1 +
config/locales/views/en.yml | 1 +
config/routes.rb | 1 +
features/support/paths.rb | 3 +++
8 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index dcb9be97318..9b06612ec01 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -61,4 +61,13 @@ def bookmarks_original_path
**params.slice(:tag_id, :collection_id, :pseud_id, :user_id).permit!
)
end
+
+ def collections_original_path
+ url_for(
+ controller: :collections,
+ action: :index,
+ only_path: true,
+ **params.slice(:tag_id, :fandom_id, :collection_id, :pseud_id, :user_id).permit!
+ )
+ end
end
diff --git a/app/views/bookmarks/index.html.erb b/app/views/bookmarks/index.html.erb
index 7293d1419f2..222b70f8a57 100755
--- a/app/views/bookmarks/index.html.erb
+++ b/app/views/bookmarks/index.html.erb
@@ -31,6 +31,7 @@
<% if @tag %>
<%= span_if_current t(".navigation.works"), tag_works_path(@tag) %>
<%= span_if_current t(".navigation.bookmarks"), tag_bookmarks_path(@tag) %>
+ <%= span_if_current t(".navigation.collections"), tag_collections_path(@tag) %>
<% end %>
<% if @facets.present? %>
<% # Filters button for narrow screens jumps to filters when JavaScript is disabled and opens filters when JavaScript is enabled %>
diff --git a/app/views/collections/index.html.erb b/app/views/collections/index.html.erb
index 448d87d0ee9..16f50271629 100755
--- a/app/views/collections/index.html.erb
+++ b/app/views/collections/index.html.erb
@@ -4,13 +4,13 @@
<%# do we need this disclaimer? %>
<%= ts("Sorry, there were no collections found.") %>
<% elsif @user %>
- <%= t(".page_heading.collections_by", collections: search_header(@collections, @query, ts("Collection")), user: @user.login) %>
+ <%= t(".page_heading.collections_by", collections: search_header(@collections, @query, ts("Collection"), @owner), user: @user.login) %>
<% elsif @collection %>
- <%= t(".page_heading.subcollections_in", subcollections: search_header(@collections, @query, ts("Subcollection")), collection: @collection.title) %>
+ <%= t(".page_heading.subcollections_in", subcollections: search_header(@collections, @query, ts("Subcollection"), @owner), collection: @collection.title) %>
<% elsif @work %>
- <%= t(".page_heading.collections_including", collections: search_header(@collections, @query, ts("Collection")), work: @work.title) %>
+ <%= t(".page_heading.collections_including", collections: search_header(@collections, @query, ts("Collection"), @owner), work: @work.title) %>
<% else %>
- <%= t(".page_heading.collections_in_the", collections: search_header(@collections, @query, ts("Collection")), archive: ArchiveConfig.APP_NAME) %>
+ <%= t(".page_heading.collections_in_the", collections: search_header(@collections, @query, ts("Collection"), @owner), archive: ArchiveConfig.APP_NAME) %>
<% end %>
diff --git a/app/views/tags/show.html.erb b/app/views/tags/show.html.erb
index 8b994f1c6a7..4e35daf39fc 100644
--- a/app/views/tags/show.html.erb
+++ b/app/views/tags/show.html.erb
@@ -8,6 +8,7 @@
<% if @tag.canonical || @tag.merger %>
<%= link_to ts("Works"), tag_works_path(@tag) %>
<%= link_to ts("Bookmarks"), tag_bookmarks_path(@tag) %>
+ <%= link_to ts("Collections"), tag_collections_path(@tag) %>
<% end %>
<% if can_wrangle? %>
<%= link_to ts("Edit"), edit_tag_path(@tag) %>
diff --git a/app/views/works/index.html.erb b/app/views/works/index.html.erb
index db80ac94b4e..56983ac6b53 100755
--- a/app/views/works/index.html.erb
+++ b/app/views/works/index.html.erb
@@ -26,6 +26,7 @@
<% if @tag && !@collection %>
<%= span_if_current ts("Works"), tag_works_path(@tag) %>
<%= span_if_current ts("Bookmarks"), tag_bookmarks_path(@tag) %>
+ <%= span_if_current ts("Collections"), tag_collections_path(@tag) %>
<% end %>
<% if @facets.present? %>
<%# Filters button for narrow screens jumps to filters when JavaScript is disabled and opens filters when JavaScript is enabled %>
diff --git a/config/locales/views/en.yml b/config/locales/views/en.yml
index 55bd4c8a751..ad5c0277741 100644
--- a/config/locales/views/en.yml
+++ b/config/locales/views/en.yml
@@ -653,6 +653,7 @@ en:
choose_fandom: choose a fandom
navigation:
bookmarks: Bookmarks
+ collections: Collections
edit: Edit Bookmark
new: Bookmark
new_external_work: Bookmark External Work
diff --git a/config/routes.rb b/config/routes.rb
index 43f2cc2e46c..22392feb8e3 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -132,6 +132,7 @@
end
resources :works
resources :bookmarks
+ resources :collections
resources :comments
resource :troubleshooting, controller: :troubleshooting, only: [:show, :update]
end
diff --git a/features/support/paths.rb b/features/support/paths.rb
index 7f8845055e5..30f84bfa476 100644
--- a/features/support/paths.rb
+++ b/features/support/paths.rb
@@ -197,6 +197,9 @@ def path_to(page_name)
when /^the bookmarks (?:tagged|page for the tag) "(.*)"$/i
step %{all indexing jobs have been run}
tag_bookmarks_path(Tag.find_by_name(Regexp.last_match(1)))
+ when /^the collections "(.*)"$/i
+ step %{all indexing jobs have been run}
+ tag_collections_path(Tag.find_by_name($1))
when /^the bookmarks in collection "(.*)"$/i
step %{all indexing jobs have been run}
collection_bookmarks_path(Collection.find_by(title: $1))
From 4c0bbd2d28be53bdc4524c3736ef6946358eca21 Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Thu, 9 Apr 2026 22:11:56 +0000
Subject: [PATCH 03/32] AO3-7147 Add appropriate buttons to tag listings of
collections
---
app/views/collections/index.html.erb | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/app/views/collections/index.html.erb b/app/views/collections/index.html.erb
index 16f50271629..6336d2d24e4 100755
--- a/app/views/collections/index.html.erb
+++ b/app/views/collections/index.html.erb
@@ -19,6 +19,18 @@
<%= ts("Navigation") %>
+ <% if @tag && !@collection %>
+ - <%= span_if_current ts("Works"), tag_works_path(@tag) %>
+ - <%= span_if_current ts("Bookmarks"), tag_bookmarks_path(@tag) %>
+ - <%= span_if_current ts("Collections"), tag_collections_path(@tag) %>
+ <% end %>
+ <% if @facets.present? %>
+ <%# Filters button for narrow screens jumps to filters when JavaScript is disabled and opens filters when JavaScript is enabled %>
+ - <%= ts("Filters") %>
+ <% end %>
+ <% if @tag && logged_in? && !@collection %>
+ - <%= render "favorite_tags/form", current_user: @current_user, favorite_tag: @favorite_tag %>
+ <% end %>
<% # Collections and Open Challenges links unless a logged in user viewing own collections page %>
<% unless logged_in? && @user && @user == current_user %>
- <%= span_if_current ts("Collections"), collections_path %>
From e31d908cdb264c7b9471b9f9dc3ac6545991293d Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Thu, 9 Apr 2026 23:40:12 +0000
Subject: [PATCH 04/32] AO3-7147 Add tag listings of collection to collection
blurbs and wrangler dashboard
---
app/views/collections/_collection_blurb.html.erb | 2 +-
app/views/tag_wranglings/_wrangler_dashboard.html.erb | 5 +++++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/app/views/collections/_collection_blurb.html.erb b/app/views/collections/_collection_blurb.html.erb
index ea52c53003d..81824b6a734 100644
--- a/app/views/collections/_collection_blurb.html.erb
+++ b/app/views/collections/_collection_blurb.html.erb
@@ -17,7 +17,7 @@
<% unless collection.tag_string.blank? %>
<% end %>
diff --git a/app/views/tag_wranglings/_wrangler_dashboard.html.erb b/app/views/tag_wranglings/_wrangler_dashboard.html.erb
index a1e0bcd38d7..3f16d4d05d5 100644
--- a/app/views/tag_wranglings/_wrangler_dashboard.html.erb
+++ b/app/views/tag_wranglings/_wrangler_dashboard.html.erb
@@ -30,6 +30,11 @@
<%= span_if_current t(".use_type_and_count", use_type: t(".use_type.external_works"), count: @counts[key]),
{ controller: :bookmarks, action: :index, tag_id: @tag } %>
+ <% elsif key == "Collections" %>
+ -
+ <%= span_if_current t(".use_type_and_count", use_type: t(".use_type.collections"), count: @counts[key]),
+ { controller: :collections, action: :index, tag_id: @tag } %>
+
<% else %>
-
From 5e50b0c8b6ae75b4a0905fea627e9104cdc9cade Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Fri, 10 Apr 2026 03:07:20 +0000
Subject: [PATCH 05/32] AO3-7147 Add links to tag collection listings to tag
pages & collection profiles
---
app/views/collection_profile/show.html.erb | 2 +-
app/views/tags/show.html.erb | 3 ++-
config/locales/views/en.yml | 3 ++-
3 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/app/views/collection_profile/show.html.erb b/app/views/collection_profile/show.html.erb
index 606d638f81a..228f8d05fc8 100644
--- a/app/views/collection_profile/show.html.erb
+++ b/app/views/collection_profile/show.html.erb
@@ -19,7 +19,7 @@
-
diff --git a/app/views/tags/show.html.erb b/app/views/tags/show.html.erb
index 4e35daf39fc..102b8b9f757 100644
--- a/app/views/tags/show.html.erb
+++ b/app/views/tags/show.html.erb
@@ -28,7 +28,8 @@
<%= t(".canonical_html",
canonical_tag_link: link_to(t(".canonical_tag"), archive_faq_path("glossary", anchor: "canonicaldef")),
filter_works_link: link_to(t(".filter_works"), tag_works_path(@tag)),
- filter_bookmarks_link: link_to(t(".filter_bookmarks"), tag_bookmarks_path(@tag))) %>
+ filter_bookmarks_link: link_to(t(".filter_bookmarks"), tag_bookmarks_path(@tag)),
+ filter_collections_link: link_to(t(".filter_collections"), tag_collections_path(@tag))) %>
<% if @tag.is_a?(Fandom) %>
<%= t(".list_fandom_tags_html", fandom_relationship_tags_link: link_to(t(".fandom_relationship_tags"), fandom_path(@tag))) %>
<% end %>
diff --git a/config/locales/views/en.yml b/config/locales/views/en.yml
index ad5c0277741..3b4814a654e 100644
--- a/config/locales/views/en.yml
+++ b/config/locales/views/en.yml
@@ -2862,7 +2862,7 @@ en:
type: Type
wrangling_status: Wrangling status
show:
- canonical_html: It's a %{canonical_tag_link}. You can use it to %{filter_works_link} and to %{filter_bookmarks_link}.
+ canonical_html: It's a %{canonical_tag_link}. You can use it to %{filter_works_link} and to %{filter_bookmarks_link}, as well as %{filter_collections_link}.
canonical_tag: canonical tag
children:
heading: 'Child tags (displaying the first %{count} of each type):'
@@ -2870,6 +2870,7 @@ en:
fandom_relationship_tags: Relationship tags in this fandom
filter_bookmarks: filter bookmarks
filter_works: filter works
+ filter_collections: filter collections
list_fandom_tags_html: You can also access a list of %{fandom_relationship_tags_link}.
synonyms: 'Tags with the same meaning:'
wrangle:
From e639700804bdd4fa15dd7b3ea7ca8159467eaeb5 Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Fri, 10 Apr 2026 04:58:32 +0000
Subject: [PATCH 06/32] AO3-7147 Implement collection listings for tags
---
app/controllers/collections_controller.rb | 111 +++++++++++++++++---
app/models/search/collection_query.rb | 18 +++-
app/models/search/collection_search_form.rb | 3 +-
app/views/collections/index.html.erb | 2 +
4 files changed, 118 insertions(+), 16 deletions(-)
diff --git a/app/controllers/collections_controller.rb b/app/controllers/collections_controller.rb
index 0877f89f6cf..87d60496eb9 100644
--- a/app/controllers/collections_controller.rb
+++ b/app/controllers/collections_controller.rb
@@ -1,4 +1,5 @@
class CollectionsController < ApplicationController
+ before_action :load_owner, only: [:index]
before_action :users_only, only: [:new, :edit, :create, :update]
before_action :load_collection_from_id, only: [:show, :edit, :update, :destroy, :confirm_delete]
before_action :collection_owners_only, only: [:edit, :update, :destroy, :confirm_delete]
@@ -30,30 +31,72 @@ def check_parent_visible
end
def index
- if params[:work_id]
- @work = Work.find(params[:work_id])
+ base_options = {
+ page: params[:page] || 1,
+ }
+ options = params[:collection_search].present? ? collection_filter_params : {}
+ options.merge!(base_options)
+
+ if logged_in? && @tag
+ @favorite_tag = @current_user.favorite_tags
+ .where(tag_id: @tag.id).first ||
+ FavoriteTag
+ .new(tag_id: @tag.id, user_id: @current_user.id)
+ end
+
+ if params[:work_id].present?
@collections = @work.approved_collections
.by_title
.for_blurb
.paginate(page: params[:page])
- elsif params[:collection_id]
- @collection = Collection.find_by!(name: params[:collection_id])
- @search = CollectionSearchForm.new({ parent_id: @collection.id, sort_column: "title.keyword" }.merge(page: params[:page]))
- @collections = @search.search_results.scope(:for_search)
- flash_search_warnings(@collections)
- @page_subtitle = t(".subcollections_page_title", collection_title: @collection.title)
- elsif params[:user_id]
- @user = User.find_by!(login: params[:user_id])
- @search = CollectionSearchForm.new({ maintainer_id: @user.id, sort_column: "title.keyword" }.merge(page: params[:page]))
+ elsif @owner.present?
+ @search = CollectionSearchForm.new(options.merge(parent: @owner))
@collections = @search.search_results.scope(:for_search)
flash_search_warnings(@collections)
- @page_subtitle = ts("%{username} - Collections", username: @user.login)
+ @pagy = pagy_query_result(@collections) if @collections.respond_to?(:total_pages)
else
@sort_and_filter = true
- @search = CollectionSearchForm.new(collection_filter_params.merge(page: params[:page]))
+ @search = CollectionSearchForm.new(options)
@collections = @search.search_results.scope(:for_search)
flash_search_warnings(@collections)
+ @pagy = pagy_query_result(@collections) if @collections.respond_to?(:total_pages)
end
+
+ # if params[:work_id]
+ # @work = Work.find(params[:work_id])
+ # @collections = @work.approved_collections
+ # .by_title
+ # .for_blurb
+ # .paginate(page: params[:page])
+ # elsif params[:collection_id]
+ # @collection = Collection.find_by!(name: params[:collection_id])
+ # @search = CollectionSearchForm.new({ parent_id: @collection.id, sort_column: "title.keyword" }.merge(page: params[:page]))
+ # @collections = @search.search_results.scope(:for_search)
+ # flash_search_warnings(@collections)
+ # @page_subtitle = t(".subcollections_page_title", collection_title: @collection.title)
+ # elsif params[:user_id]
+ # @user = User.find_by!(login: params[:user_id])
+ # @search = CollectionSearchForm.new({ maintainer_id: @user.id, sort_column: "title.keyword" }.merge(page: params[:page]))
+ # @collections = @search.search_results.scope(:for_search)
+ # flash_search_warnings(@collections)
+ # @page_subtitle = ts("%{username} - Collections", username: @user.login)
+ # elsif params[:tag_id]
+ # if logged_in?
+ # @favorite_tag = @current_user.favorite_tags
+ # .where(tag_id: @tag.id).first ||
+ # FavoriteTag
+ # .new(tag_id: @tag.id, user_id: @current_user.id)
+ # end
+ # @sort_and_filter = true
+ # @search = CollectionSearchForm.new({ tag_id: @tag.id, sort_column: "created_at" }.merge(page: params[:page]))
+ # @collections = @search.search_results.scope(:for_search)
+ # flash_search_warnings(@collections)
+ # else
+ # @sort_and_filter = true
+ # @search = CollectionSearchForm.new(collection_filter_params.merge(page: params[:page]))
+ # @collections = @search.search_results.scope(:for_search)
+ # flash_search_warnings(@collections)
+ # end
end
# display challenges that are currently taking signups
@@ -191,6 +234,48 @@ def destroy
redirect_to(collections_path)
end
+ protected
+
+ def load_owner
+ if params[:user_id].present?
+ @user = User.find_by!(login: params[:user_id])
+ end
+ if params[:collection_id].present?
+ @collection = Collection.find_by!(name: params[:collection_id])
+ end
+ if params[:tag_id]
+ @tag = Tag.find_by_name(params[:tag_id])
+ unless @tag && @tag.is_a?(Tag)
+ raise ActiveRecord::RecordNotFound, "Couldn't find tag named '#{params[:tag_id]}'"
+ end
+ unless @tag.canonical?
+ if @tag.merger.present?
+ redirect_to tag_collections_path(@tag.merger) and return
+ else
+ redirect_to(tag_path(@tag)) && return
+ end
+ end
+ end
+ @owner = @user || @collection || @tag
+ end
+
+ def index_page_title
+ # TODO: uhhhh. it's probably not this.
+ if @owner.present?
+ owner_name = case @owner.class.to_s
+ when 'User'
+ @owner.login
+ when 'Collection'
+ @owner.title
+ else
+ @owner.try(:name)
+ end
+ "#{owner_name} - Collections".html_safe
+ else
+ "Latest Collections"
+ end
+ end
+
private
def collection_filter_params
diff --git a/app/models/search/collection_query.rb b/app/models/search/collection_query.rb
index 61792360dad..1215e9939f8 100644
--- a/app/models/search/collection_query.rb
+++ b/app/models/search/collection_query.rb
@@ -24,6 +24,7 @@ def parsed_included_tags
# Combine the available filters
def filters
+ add_owner
[
multifandom_filter,
signup_open_filter,
@@ -44,6 +45,19 @@ def queries
].flatten.compact
end
+ def add_owner
+ owner = options[:parent]
+ case owner
+ when Tag
+ options[:filter_ids] ||= []
+ options[:filter_ids] << owner.id
+ when User
+ options[:maintainer_id] = owner.id
+ when Collection
+ options[:parent_id] = owner.id
+ end
+ end
+
####################
# FILTERS
####################
@@ -86,9 +100,9 @@ def parent_filter
end
def filter_id_filter
- return if filter_ids.blank?
+ return if options[:filter_ids].blank?
- filter_ids.map { |filter_id| term_filter(:filter_ids, filter_id) }
+ options[:filter_ids].map { |filter_id| term_filter(:filter_ids, filter_id) }
end
def named_tag_inclusion_filter
diff --git a/app/models/search/collection_search_form.rb b/app/models/search/collection_search_form.rb
index 7dd45aadf29..0ba3a45bc6e 100644
--- a/app/models/search/collection_search_form.rb
+++ b/app/models/search/collection_search_form.rb
@@ -7,10 +7,11 @@ class CollectionSearchForm
challenge_type
closed
maintainer_id
+ filter_ids
+ parent_id
moderated
multifandom
page
- parent_id
per_page
signup_open
sort_column
diff --git a/app/views/collections/index.html.erb b/app/views/collections/index.html.erb
index 6336d2d24e4..a238b97431a 100755
--- a/app/views/collections/index.html.erb
+++ b/app/views/collections/index.html.erb
@@ -9,6 +9,8 @@
<%= t(".page_heading.subcollections_in", subcollections: search_header(@collections, @query, ts("Subcollection"), @owner), collection: @collection.title) %>
<% elsif @work %>
<%= t(".page_heading.collections_including", collections: search_header(@collections, @query, ts("Collection"), @owner), work: @work.title) %>
+ <% elsif @tag %>
+ <%= "whoa it's a tag" %>
<% else %>
<%= t(".page_heading.collections_in_the", collections: search_header(@collections, @query, ts("Collection"), @owner), archive: ArchiveConfig.APP_NAME) %>
<% end %>
From b097682efe56ac622e2c0fc6c137b3bb2fbf79bf Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Fri, 10 Apr 2026 05:49:31 +0000
Subject: [PATCH 07/32] AO3-7144 Simplify logic for collection page headings
---
app/controllers/collections_controller.rb | 5 ++++-
app/helpers/search_helper.rb | 2 ++
app/views/collections/index.html.erb | 15 +++++----------
config/locales/views/en.yml | 6 +++---
4 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/app/controllers/collections_controller.rb b/app/controllers/collections_controller.rb
index 87d60496eb9..80444925d76 100644
--- a/app/controllers/collections_controller.rb
+++ b/app/controllers/collections_controller.rb
@@ -240,6 +240,9 @@ def load_owner
if params[:user_id].present?
@user = User.find_by!(login: params[:user_id])
end
+ if params[:work_id].present?
+ @work = Work.find(params[:work_id])
+ end
if params[:collection_id].present?
@collection = Collection.find_by!(name: params[:collection_id])
end
@@ -256,7 +259,7 @@ def load_owner
end
end
end
- @owner = @user || @collection || @tag
+ @owner = @user || @work || @collection || @tag
end
def index_page_title
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index 9b06612ec01..11d36df0842 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -27,6 +27,8 @@ def search_header(collection, search, item_name, parent=nil)
header << ts("by %{username}", username: parent.login)
when Language
header << ts("in %{language}", language: parent.name)
+ when Work
+ header << ts("including %{work}", work: parent.title)
end
header << ts("in %{tag_link}", tag_link: link_to_tag_with_text(parent, parent.name)) if parent.is_a?(Tag)
diff --git a/app/views/collections/index.html.erb b/app/views/collections/index.html.erb
index a238b97431a..b2c5bffd341 100755
--- a/app/views/collections/index.html.erb
+++ b/app/views/collections/index.html.erb
@@ -1,18 +1,13 @@
<% if @collections.empty? %>
- <%# do we need this disclaimer? %>
- <%= ts("Sorry, there were no collections found.") %>
- <% elsif @user %>
- <%= t(".page_heading.collections_by", collections: search_header(@collections, @query, ts("Collection"), @owner), user: @user.login) %>
+ <%= t(".page_heading.sorry") %>
+ <% elsif @user || @tag || @work %>
+ <%= search_header(@collections, @query, t(".page_heading.collection"), @owner) %>
<% elsif @collection %>
- <%= t(".page_heading.subcollections_in", subcollections: search_header(@collections, @query, ts("Subcollection"), @owner), collection: @collection.title) %>
- <% elsif @work %>
- <%= t(".page_heading.collections_including", collections: search_header(@collections, @query, ts("Collection"), @owner), work: @work.title) %>
- <% elsif @tag %>
- <%= "whoa it's a tag" %>
+ <%= search_header(@collections, @query, t(".page_heading.subcollection"), @owner) %>
<% else %>
- <%= t(".page_heading.collections_in_the", collections: search_header(@collections, @query, ts("Collection"), @owner), archive: ArchiveConfig.APP_NAME) %>
+ <%= t(".page_heading.collections_in_the", collections: search_header(@collections, @query, t(".page_heading.collection"), @owner), archive: ArchiveConfig.APP_NAME) %>
<% end %>
diff --git a/config/locales/views/en.yml b/config/locales/views/en.yml
index 3b4814a654e..cc86557046a 100644
--- a/config/locales/views/en.yml
+++ b/config/locales/views/en.yml
@@ -804,10 +804,10 @@ en:
label: Multifandom
index:
page_heading:
- collections_by: "%{collections} by %{user}"
+ collection: Collection
collections_in_the: "%{collections} in the %{archive}"
- collections_including: "%{collections} including %{work}"
- subcollections_in: "%{subcollections} in %{collection}"
+ sorry: Sorry, there were no collections found.
+ subcollection: Subcollection
sidebar:
bookmarks: Bookmarked Items (%{count})
challenge_settings: Challenge Settings
From e191a7d67ecbcee1cb09a1fac4f8331dc6594518 Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Fri, 10 Apr 2026 07:23:30 +0000
Subject: [PATCH 08/32] AO3-7147 Add filter module to tag collection listings
page
---
app/controllers/collections_controller.rb | 58 ++---------------------
app/helpers/search_helper.rb | 2 +-
app/views/collections/_filters.html.erb | 5 ++
app/views/collections/index.html.erb | 4 +-
4 files changed, 12 insertions(+), 57 deletions(-)
diff --git a/app/controllers/collections_controller.rb b/app/controllers/collections_controller.rb
index 80444925d76..49a600888e8 100644
--- a/app/controllers/collections_controller.rb
+++ b/app/controllers/collections_controller.rb
@@ -50,6 +50,9 @@ def index
.for_blurb
.paginate(page: params[:page])
elsif @owner.present?
+ if @tag.present?
+ @sort_and_filter = true
+ end
@search = CollectionSearchForm.new(options.merge(parent: @owner))
@collections = @search.search_results.scope(:for_search)
flash_search_warnings(@collections)
@@ -61,42 +64,6 @@ def index
flash_search_warnings(@collections)
@pagy = pagy_query_result(@collections) if @collections.respond_to?(:total_pages)
end
-
- # if params[:work_id]
- # @work = Work.find(params[:work_id])
- # @collections = @work.approved_collections
- # .by_title
- # .for_blurb
- # .paginate(page: params[:page])
- # elsif params[:collection_id]
- # @collection = Collection.find_by!(name: params[:collection_id])
- # @search = CollectionSearchForm.new({ parent_id: @collection.id, sort_column: "title.keyword" }.merge(page: params[:page]))
- # @collections = @search.search_results.scope(:for_search)
- # flash_search_warnings(@collections)
- # @page_subtitle = t(".subcollections_page_title", collection_title: @collection.title)
- # elsif params[:user_id]
- # @user = User.find_by!(login: params[:user_id])
- # @search = CollectionSearchForm.new({ maintainer_id: @user.id, sort_column: "title.keyword" }.merge(page: params[:page]))
- # @collections = @search.search_results.scope(:for_search)
- # flash_search_warnings(@collections)
- # @page_subtitle = ts("%{username} - Collections", username: @user.login)
- # elsif params[:tag_id]
- # if logged_in?
- # @favorite_tag = @current_user.favorite_tags
- # .where(tag_id: @tag.id).first ||
- # FavoriteTag
- # .new(tag_id: @tag.id, user_id: @current_user.id)
- # end
- # @sort_and_filter = true
- # @search = CollectionSearchForm.new({ tag_id: @tag.id, sort_column: "created_at" }.merge(page: params[:page]))
- # @collections = @search.search_results.scope(:for_search)
- # flash_search_warnings(@collections)
- # else
- # @sort_and_filter = true
- # @search = CollectionSearchForm.new(collection_filter_params.merge(page: params[:page]))
- # @collections = @search.search_results.scope(:for_search)
- # flash_search_warnings(@collections)
- # end
end
# display challenges that are currently taking signups
@@ -246,7 +213,7 @@ def load_owner
if params[:collection_id].present?
@collection = Collection.find_by!(name: params[:collection_id])
end
- if params[:tag_id]
+ if params[:tag_id].present?
@tag = Tag.find_by_name(params[:tag_id])
unless @tag && @tag.is_a?(Tag)
raise ActiveRecord::RecordNotFound, "Couldn't find tag named '#{params[:tag_id]}'"
@@ -262,23 +229,6 @@ def load_owner
@owner = @user || @work || @collection || @tag
end
- def index_page_title
- # TODO: uhhhh. it's probably not this.
- if @owner.present?
- owner_name = case @owner.class.to_s
- when 'User'
- @owner.login
- when 'Collection'
- @owner.title
- else
- @owner.try(:name)
- end
- "#{owner_name} - Collections".html_safe
- else
- "Latest Collections"
- end
- end
-
private
def collection_filter_params
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index 11d36df0842..5c4fd240af8 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -69,7 +69,7 @@ def collections_original_path
controller: :collections,
action: :index,
only_path: true,
- **params.slice(:tag_id, :fandom_id, :collection_id, :pseud_id, :user_id).permit!
+ **params.slice(:tag_id, :collection_id, :user_id, :work_id).permit!
)
end
end
diff --git a/app/views/collections/_filters.html.erb b/app/views/collections/_filters.html.erb
index 03e2b280107..e26c2a6772b 100644
--- a/app/views/collections/_filters.html.erb
+++ b/app/views/collections/_filters.html.erb
@@ -135,6 +135,11 @@
+
+ <%= hidden_field_tag("collection_id", @collection.id) if @collection %>
+ <%= hidden_field_tag("tag_id", @tag.to_param) if @tag %>
+ <%= hidden_field_tag("user_id", @user.login) if @user %>
+
<% end %>
<% # On narrow screens, link jumps to top of index when JavaScript is disabled and closes filters when JavaScript is enabled %>
diff --git a/app/views/collections/index.html.erb b/app/views/collections/index.html.erb
index b2c5bffd341..ac0f8645dab 100755
--- a/app/views/collections/index.html.erb
+++ b/app/views/collections/index.html.erb
@@ -29,7 +29,7 @@
- <%= render "favorite_tags/form", current_user: @current_user, favorite_tag: @favorite_tag %>
<% end %>
<% # Collections and Open Challenges links unless a logged in user viewing own collections page %>
- <% unless logged_in? && @user && @user == current_user %>
+ <% unless @tag || (logged_in? && @user && @user == current_user) %>
- <%= span_if_current ts("Collections"), collections_path %>
- <%= link_to ts("Open Challenges"), list_challenges_collections_path %>
<% end %>
@@ -42,7 +42,7 @@
<% # Logged in collection maintainer on own collection gets link for New Subcollection and all other logged in users get New Collection link %>
<% if @collection && !@collection.parent && @collection.user_is_maintainer?(current_user) %>
- <%= link_to ts("New Subcollection"), new_collection_collection_path(@collection) %>
- <% else %>
+ <% elsif !@tag %>
- <%= link_to ts("New Collection"), new_collection_path %>
<% end %>
<% end %>
From ac32b8932f57ff6bd110666e455c9bfde1b272cd Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Sat, 11 Apr 2026 00:35:31 +0000
Subject: [PATCH 09/32] AO3-7147 Correct page title for tag collection listings
and correct filter_ids handling
---
app/controllers/collections_controller.rb | 14 ++++++++++++++
app/models/search/collection_query.rb | 5 +++--
config/locales/controllers/en.yml | 6 +++++-
3 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/app/controllers/collections_controller.rb b/app/controllers/collections_controller.rb
index 49a600888e8..028caec6295 100644
--- a/app/controllers/collections_controller.rb
+++ b/app/controllers/collections_controller.rb
@@ -37,6 +37,8 @@ def index
options = params[:collection_search].present? ? collection_filter_params : {}
options.merge!(base_options)
+ @page_title = index_page_title
+
if logged_in? && @tag
@favorite_tag = @current_user.favorite_tags
.where(tag_id: @tag.id).first ||
@@ -229,6 +231,18 @@ def load_owner
@owner = @user || @work || @collection || @tag
end
+ def index_page_title
+ if @collection.present?
+ t(".page_title.subcollection", collection_title: @collection.title)
+ elsif @user.present?
+ t(".page_title.user", user_name: @user.login)
+ elsif @tag.present?
+ t(".page_title.tag", tag_name: @tag.name)
+ else
+ t(".page_title.general")
+ end
+ end
+
private
def collection_filter_params
diff --git a/app/models/search/collection_query.rb b/app/models/search/collection_query.rb
index 1215e9939f8..3e305c85de7 100644
--- a/app/models/search/collection_query.rb
+++ b/app/models/search/collection_query.rb
@@ -47,6 +47,7 @@ def queries
def add_owner
owner = options[:parent]
+ # should maybe be an if statement?
case owner
when Tag
options[:filter_ids] ||= []
@@ -100,9 +101,9 @@ def parent_filter
end
def filter_id_filter
- return if options[:filter_ids].blank?
+ return if filter_ids.blank?
- options[:filter_ids].map { |filter_id| term_filter(:filter_ids, filter_id) }
+ filter_ids.map { |filter_id| term_filter(:filter_ids, filter_id) }
end
def named_tag_inclusion_filter
diff --git a/config/locales/controllers/en.yml b/config/locales/controllers/en.yml
index fe3f3e817ff..fee56e2ed23 100644
--- a/config/locales/controllers/en.yml
+++ b/config/locales/controllers/en.yml
@@ -123,7 +123,11 @@ en:
page_title: "%{collection_title} - Profile"
collections:
index:
- subcollections_page_title: "%{collection_title} - Subcollections"
+ page_title:
+ general: "Collections"
+ subcollection: "%{collection_title} - Subcollections"
+ tag: "%{tag_name} - Collections"
+ user: "%{user_name} - Collections"
comments:
check_blocked:
parent: Sorry, you have been blocked by one or more of this work's creators.
From 8ffaeff9ba9c05bf15d1ff17479220d7c178f8e1 Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Sat, 11 Apr 2026 03:55:21 +0000
Subject: [PATCH 10/32] AO3-7147 Add tests for tag collection listings
---
app/controllers/collections_controller.rb | 2 +-
app/views/collections/index.html.erb | 11 +-
.../collections/collection_browse.feature | 14 +-
.../collections/collection_navigation.feature | 2 +-
.../collections/collection_taglisting.feature | 120 ++++++++++++++++++
features/step_definitions/collection_steps.rb | 6 +
6 files changed, 147 insertions(+), 8 deletions(-)
create mode 100644 features/collections/collection_taglisting.feature
diff --git a/app/controllers/collections_controller.rb b/app/controllers/collections_controller.rb
index 028caec6295..c9bb9a6eeb6 100644
--- a/app/controllers/collections_controller.rb
+++ b/app/controllers/collections_controller.rb
@@ -246,7 +246,7 @@ def index_page_title
private
def collection_filter_params
- params.permit(:commit, collection_search: [
+ params.permit(:commit, :tag_id, collection_search: [
:title, :challenge_type, :moderated, :multifandom, :closed, :tag,
:sort_column, :sort_direction
])[:collection_search] || {}
diff --git a/app/views/collections/index.html.erb b/app/views/collections/index.html.erb
index ac0f8645dab..3fb9519aa56 100755
--- a/app/views/collections/index.html.erb
+++ b/app/views/collections/index.html.erb
@@ -1,8 +1,6 @@
- <% if @collections.empty? %>
- <%= t(".page_heading.sorry") %>
- <% elsif @user || @tag || @work %>
+ <% if @user || @tag || @work %>
<%= search_header(@collections, @query, t(".page_heading.collection"), @owner) %>
<% elsif @collection %>
<%= search_header(@collections, @query, t(".page_heading.subcollection"), @owner) %>
@@ -11,6 +9,13 @@
<% end %>
+<%# TODO: Do we still need this now that there's a 0 in the search header? %>
+<% if @collections.empty? %>
+
+ <%= t(".page_heading.sorry") %>
+
+<% end %>
+
diff --git a/features/collections/collection_browse.feature b/features/collections/collection_browse.feature
index 223fdbe13e2..e2984c6d4b7 100644
--- a/features/collections/collection_browse.feature
+++ b/features/collections/collection_browse.feature
@@ -179,7 +179,7 @@ Feature: Collection
And I should not see "Some Other Collection"
And I should not see "Surprise Presents"
- Scenario: Filter collections by non-canonical and non-existent collection tags
+ Scenario: Filter collections by canonicals, synonyms, noncanonicals, and non-existent collection tags
Given a set of collections for searching
When I go to the collections page
@@ -187,8 +187,8 @@ Feature: Collection
And I press "Sort and Filter"
Then I should see "Some Test Collection"
And I should see "Some Other Collection"
+ And I should see "Surprise Presents"
But I should not see "Another Plain Collection"
- And I should not see "Surprise Presents"
And I should not see "Another Gift Swap"
And I should not see "On Demand"
When I fill in "collection_search_tag" with "The Best Tag,The Better Tag"
@@ -204,7 +204,15 @@ Feature: Collection
Then I should see "Some Test Collection"
And I should see "Some Other Collection"
And I should see "Another Plain Collection"
- But I should not see "Surprise Presents"
+ And I should see "Surprise Presents"
+ And I should not see "Another Gift Swap"
+ And I should not see "On Demand"
+ When I fill in "collection_search_tag" with "TBT"
+ And I press "Sort and Filter"
+ Then I should see "Surprise Presents"
+ But I should not see "Some Test Collection"
+ And I should not see "Some Other Collection"
+ And I should not see "Another Plain Collection"
And I should not see "Another Gift Swap"
And I should not see "On Demand"
diff --git a/features/collections/collection_navigation.feature b/features/collections/collection_navigation.feature
index 2b768d9b1c0..1d6822c4e5c 100644
--- a/features/collections/collection_navigation.feature
+++ b/features/collections/collection_navigation.feature
@@ -32,7 +32,7 @@ Feature: Basic collection navigation
Then I should see "About My Collection (my_collection)"
And I should see "Maintainers: mod"
When I follow "Subcollections (0)"
- Then I should see "Challenges/Subcollections in My Collection"
+ Then I should see "Subcollections in My Collection"
And I should see "Sorry, there were no collections found."
When I follow "Fandoms (1)"
Then I should see "New Fandom (1)"
diff --git a/features/collections/collection_taglisting.feature b/features/collections/collection_taglisting.feature
new file mode 100644
index 00000000000..2b12b20a7e5
--- /dev/null
+++ b/features/collections/collection_taglisting.feature
@@ -0,0 +1,120 @@
+@collections
+Feature: Collection
+ In order to have an archive full of collections
+ As a humble user
+ I want to locate and browse through tag collection listings
+
+ Scenario: Tags and synonyms of the tag show up in the tag's collection listing
+ Given a set of collections for searching
+ When I go to the collections page
+ And I follow "The Best Tag"
+ Then I should see the page title "The Best Tag - Collections"
+ And I should see "The Best Tag" within "h2.heading"
+ And I should see "3 Collections" within "h2.heading"
+ And I should not see "Example Archive" within "h2.heading"
+ And I should see "Some Test Collection"
+ And I should see "Some Other Collection"
+ And I should see "Surprise Presents"
+ But I should not see "Another Plain Collection"
+ And I should not see "Another Gift Swap"
+ And I should not see "On Demand"
+
+ Scenario: We can further filter a tag's collection listing with collection_search_tag
+ Given a set of collections for searching
+ When I go to the collections page
+ And I follow "The Best Tag"
+ Then I should see "The Best Tag" within "h2.heading"
+ And I should see "3 Collections" within "h2.heading"
+ And I should not see "Example Archive" within "h2.heading"
+ When I fill in "collection_search_tag" with "The Better Tag"
+ And I press "Sort and Filter"
+ Then I should see "The Best Tag" within "h2.heading"
+ And I should see "1 Collection" within "h2.heading"
+ And I should not see "Example Archive" within "h2.heading"
+ And I should see "Some Test Collection"
+ But I should not see "Some Other Collection"
+ And I should not see "Surprise Presents"
+ And I should not see "Another Plain Collection"
+ And I should not see "Another Gift Swap"
+ And I should not see "On Demand"
+
+ Scenario: We can filter a tag's collection listing with radio buttons
+ Given a set of collections for searching
+ When I go to the collections page
+ And I follow "The Best Tag"
+ Then I should see "The Best Tag" within "h2.heading"
+ And I should see "3 Collections" within "h2.heading"
+ And I should not see "Example Archive" within "h2.heading"
+ When I choose "collection_search_challenge_type_giftexchange"
+ And I press "Sort and Filter"
+ Then I should see "The Best Tag" within "h2.heading"
+ And I should see "1 Collection" within "h2.heading"
+ And I should not see "Example Archive" within "h2.heading"
+ And I should see "Surprise Presents"
+ And I should not see "Some Test Collection"
+ But I should not see "Some Other Collection"
+ And I should not see "Another Plain Collection"
+ And I should not see "Another Gift Swap"
+ And I should not see "On Demand"
+
+ Scenario: We can find collection listings for a tag through a collection profile
+ Given a set of collections for searching
+ When I go to "Some Test Collection" collection's page
+ And I follow "Profile"
+ And I follow "The Best Tag" within ".tags"
+ Then I should see "The Best Tag" within "h2.heading"
+ And I should see "3 Collections" within "h2.heading"
+ And I should not see "Example Archive" within "h2.heading"
+
+ Scenario: We can find collection listings for a tag through the tag profile
+ Given a set of collections for searching
+ When I view the tag "The Best Tag"
+ And I follow "filter collections"
+ Then I should see "The Best Tag" within "h2.heading"
+ And I should see "3 Collections" within "h2.heading"
+ And I should not see "Example Archive" within "h2.heading"
+
+ Scenario: We can find collection listings for a tag through the buttons at the top of the tag profile and its works/bookmarks pages
+ Given a set of collections for searching
+ When I view the tag "The Best Tag"
+ And I follow "Collections" within ".primary.header.module"
+ Then I should see "The Best Tag" within "h2.heading"
+ And I should see "3 Collections" within "h2.heading"
+ And I should not see "Example Archive" within "h2.heading"
+ When I follow "Works" within "#main"
+ Then I should see "The Best Tag" within "h2.heading"
+ And I should see "Works" within "h2.heading"
+ And I should not see "Example Archive" within "h2.heading"
+ When I follow "Collections" within "#main"
+ Then I should see "The Best Tag" within "h2.heading"
+ And I should see "3 Collections" within "h2.heading"
+ And I should not see "Example Archive" within "h2.heading"
+ When I follow "Bookmarks" within "#main"
+ Then I should see "The Best Tag" within "h2.heading"
+ And I should see "Bookmarked Items" within "h2.heading"
+ And I should not see "Example Archive" within "h2.heading"
+ When I follow "Collections" within "#main"
+ Then I should see "The Best Tag" within "h2.heading"
+ And I should see "3 Collections" within "h2.heading"
+ And I should not see "Example Archive" within "h2.heading"
+
+ Scenario: A tag's collection listings should update when a collection's tags are edited
+ Given a set of collections for searching
+ When I am logged in as the owner of "Some Other Collection"
+ And I go to "Some Other Collection" collection's page
+ And I follow "Profile"
+ And I follow "Collection Settings"
+ And I fill in "Collection Tags" with ""
+ And I press "Update"
+ And all indexing jobs have been run
+ And I view the tag "The Best Tag"
+ And I follow "Collections" within ".primary.header.module"
+ Then I should see "The Best Tag" within "h2.heading"
+ And I should see "2 Collections" within "h2.heading"
+ And I should not see "Example Archive" within "h2.heading"
+ And I should see "Some Test Collection"
+ And I should see "Surprise Presents"
+ But I should not see "Some Other Collection"
+ And I should not see "Another Plain Collection"
+ And I should not see "Another Gift Swap"
+ And I should not see "On Demand"
\ No newline at end of file
diff --git a/features/step_definitions/collection_steps.rb b/features/step_definitions/collection_steps.rb
index 3b1307e5747..c4f36884398 100644
--- a/features/step_definitions/collection_steps.rb
+++ b/features/step_definitions/collection_steps.rb
@@ -138,6 +138,11 @@
end
Given "a set of collections for searching" do
+ thebest = Fandom.where(name: "The Best Tag", canonical: true).first_or_create
+ # thebetter = Fandom.where(name: "The Better Tag", canonical: true).first_or_create
+ tbt = Fandom.find_or_create_by(name: "TBT")
+ tbt.reload.merger = thebest
+ tbt.save
profile = CollectionProfile.create!(faq: "- What is this test thing?
- It's a test collection
",
intro: "Welcome to the test collection",
rules: "Be nice to testers")
@@ -159,6 +164,7 @@
:moderated,
name: "surprisetest",
title: "Surprise Presents",
+ tag_string: "TBT",
challenge: FactoryBot.create(:gift_exchange))
FactoryBot.create(:collection,
name: "swaptest",
From 8c15d37b60c2d342a2d5e9e6f018ac9946d1245c Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Sat, 11 Apr 2026 04:40:54 +0000
Subject: [PATCH 11/32] AO3-7147 Correct sort order of collections owned by a
user or collection
---
app/models/search/collection_query.rb | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/app/models/search/collection_query.rb b/app/models/search/collection_query.rb
index 3e305c85de7..142f2bf09dd 100644
--- a/app/models/search/collection_query.rb
+++ b/app/models/search/collection_query.rb
@@ -54,8 +54,12 @@ def add_owner
options[:filter_ids] << owner.id
when User
options[:maintainer_id] = owner.id
+ options[:sort_column] = "title.keyword"
+ options[:sort_direction] = "asc"
when Collection
options[:parent_id] = owner.id
+ options[:sort_column] = "title.keyword"
+ options[:sort_direction] = "asc"
end
end
From 34b1e48d12e8015a70dce168e88040bca1f64ced Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Sat, 11 Apr 2026 04:41:58 +0000
Subject: [PATCH 12/32] AO3-7144 Update test for subcollections index's page
title
---
spec/controllers/collections_controller_spec.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/spec/controllers/collections_controller_spec.rb b/spec/controllers/collections_controller_spec.rb
index fe38dc191eb..c1e6b837622 100644
--- a/spec/controllers/collections_controller_spec.rb
+++ b/spec/controllers/collections_controller_spec.rb
@@ -46,9 +46,9 @@
run_all_indexing_jobs
end
- it "assigns subtitle with collection title and subcollections" do
+ it "assigns title with collection title and subcollections" do
get :index, params: { collection_id: gift_exchange_collection.name }
- expect(assigns[:page_subtitle]).to eq("#{gift_exchange_collection.title} - Subcollections")
+ expect(assigns[:page_title]).to eq("#{gift_exchange_collection.title} - Subcollections")
end
context "collections index" do
From fee110ef61f3971bbe79fe76b200a04419f385b1 Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Sat, 11 Apr 2026 17:51:16 +0000
Subject: [PATCH 13/32] AO3-7147 Remove favorite tags section & i18n
collections index page
---
app/controllers/collections_controller.rb | 7 ------
app/views/collections/index.html.erb | 29 ++++++++++-------------
config/locales/views/en.yml | 14 +++++++++++
3 files changed, 27 insertions(+), 23 deletions(-)
diff --git a/app/controllers/collections_controller.rb b/app/controllers/collections_controller.rb
index c9bb9a6eeb6..f4397e7f337 100644
--- a/app/controllers/collections_controller.rb
+++ b/app/controllers/collections_controller.rb
@@ -39,13 +39,6 @@ def index
@page_title = index_page_title
- if logged_in? && @tag
- @favorite_tag = @current_user.favorite_tags
- .where(tag_id: @tag.id).first ||
- FavoriteTag
- .new(tag_id: @tag.id, user_id: @current_user.id)
- end
-
if params[:work_id].present?
@collections = @work.approved_collections
.by_title
diff --git a/app/views/collections/index.html.erb b/app/views/collections/index.html.erb
index 3fb9519aa56..8674036790d 100755
--- a/app/views/collections/index.html.erb
+++ b/app/views/collections/index.html.erb
@@ -19,41 +19,38 @@
-<%= ts("Navigation") %>
+<%= t(".landmark.navigation") %>
<% if @tag && !@collection %>
- - <%= span_if_current ts("Works"), tag_works_path(@tag) %>
- - <%= span_if_current ts("Bookmarks"), tag_bookmarks_path(@tag) %>
- - <%= span_if_current ts("Collections"), tag_collections_path(@tag) %>
+ - <%= span_if_current t(".navigation.works"), tag_works_path(@tag) %>
+ - <%= span_if_current t(".navigation.bookmarks"), tag_bookmarks_path(@tag) %>
+ - <%= span_if_current t(".navigation.collections"), tag_collections_path(@tag) %>
<% end %>
<% if @facets.present? %>
<%# Filters button for narrow screens jumps to filters when JavaScript is disabled and opens filters when JavaScript is enabled %>
- - <%= ts("Filters") %>
- <% end %>
- <% if @tag && logged_in? && !@collection %>
- - <%= render "favorite_tags/form", current_user: @current_user, favorite_tag: @favorite_tag %>
+ - <%= t(".navigation.filters") %>
<% end %>
<% # Collections and Open Challenges links unless a logged in user viewing own collections page %>
<% unless @tag || (logged_in? && @user && @user == current_user) %>
- - <%= span_if_current ts("Collections"), collections_path %>
- - <%= link_to ts("Open Challenges"), list_challenges_collections_path %>
+ - <%= span_if_current t(".navigation.all_collections"), collections_path %>
+ - <%= link_to t(".navigation.open_challenges"), list_challenges_collections_path %>
<% end %>
<% if logged_in? %>
<% # Logged in user on own collections index gets links for user Collections and Manage Collection Items %>
<% if @user && @user == current_user %>
- - <%= span_if_current ts("Collections"), user_collections_path(@user) %>
- - <%= link_to ts("Manage Collection Items"), user_collection_items_path(@user) %>
+ - <%= span_if_current t(".navigation.user_collections"), user_collections_path(@user) %>
+ - <%= link_to t(".navigation.manage_collection"), user_collection_items_path(@user) %>
<% end %>
<% # Logged in collection maintainer on own collection gets link for New Subcollection and all other logged in users get New Collection link %>
<% if @collection && !@collection.parent && @collection.user_is_maintainer?(current_user) %>
- - <%= link_to ts("New Subcollection"), new_collection_collection_path(@collection) %>
+ - <%= link_to t(".navigation.new_subcollection"), new_collection_collection_path(@collection) %>
<% elsif !@tag %>
- - <%= link_to ts("New Collection"), new_collection_path %>
+ - <%= link_to t(".navigation.new_collection"), new_collection_path %>
<% end %>
<% end %>
<% if @sort_and_filter %>
<% # Filters button for narrow screens jumps to filters when JavaScript is disabled and opens filters when JavaScript is enabled %>
- - <%= ts("Filters") %>
+ - <%= t(".navigation.filters") %>
<% end %>
@@ -62,7 +59,7 @@
<%= will_paginate @collections %>
- <%= ts("List of Collections") %>
+ <%= t(".landmark.list_collections") %>
<% @collections.each do |collection| %>
<%= render :partial => "collection_blurb", :locals => {:collection => collection} %>
diff --git a/config/locales/views/en.yml b/config/locales/views/en.yml
index d8a86508efa..249fc73dee5 100644
--- a/config/locales/views/en.yml
+++ b/config/locales/views/en.yml
@@ -805,6 +805,20 @@ en:
footnote: Use this if your collection is not fandom-specific.
label: Multifandom
index:
+ landmark:
+ navigation: Navigation
+ list_collections: List of Collections
+ navigation:
+ all_collections: Collections
+ bookmarks: Bookmarks
+ collections: Collections
+ filters: Filters
+ manage_collection: Manage Collection Items
+ new_collection: New Collection
+ new_subcollection: New Subcollection
+ open_challenges: Open Challenges
+ user_collections: Collections
+ works: Works
page_heading:
collection: Collection
collections_in_the: "%{collections} in the %{archive}"
From 8b710ca9ecc93a234a838c874b0b298957424ca0 Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Tue, 14 Apr 2026 23:58:31 +0000
Subject: [PATCH 14/32] AO3-7144 AO3-7147 Appease linter
---
app/controllers/collections_controller.rb | 30 ++++++-------------
app/helpers/search_helper.rb | 3 +-
app/models/search/collection_query.rb | 22 +++++++-------
.../collections/_collection_blurb.html.erb | 2 +-
app/views/tags/show.html.erb | 10 +++----
app/views/works/index.html.erb | 12 ++++----
config/locales/helpers/en.yml | 4 +++
config/locales/views/en.yml | 17 +++++++++--
features/support/paths.rb | 2 +-
9 files changed, 54 insertions(+), 48 deletions(-)
diff --git a/app/controllers/collections_controller.rb b/app/controllers/collections_controller.rb
index f4397e7f337..3a54cc18417 100644
--- a/app/controllers/collections_controller.rb
+++ b/app/controllers/collections_controller.rb
@@ -32,7 +32,7 @@ def check_parent_visible
def index
base_options = {
- page: params[:page] || 1,
+ page: params[:page] || 1
}
options = params[:collection_search].present? ? collection_filter_params : {}
options.merge!(base_options)
@@ -45,9 +45,7 @@ def index
.for_blurb
.paginate(page: params[:page])
elsif @owner.present?
- if @tag.present?
- @sort_and_filter = true
- end
+ @sort_and_filter = @tag.present?
@search = CollectionSearchForm.new(options.merge(parent: @owner))
@collections = @search.search_results.scope(:for_search)
flash_search_warnings(@collections)
@@ -199,26 +197,16 @@ def destroy
protected
def load_owner
- if params[:user_id].present?
- @user = User.find_by!(login: params[:user_id])
- end
- if params[:work_id].present?
- @work = Work.find(params[:work_id])
- end
- if params[:collection_id].present?
- @collection = Collection.find_by!(name: params[:collection_id])
- end
+ @user = User.find_by!(login: params[:user_id]) if params[:user_id].present?
+ @work = Work.find(params[:work_id]) if params[:work_id].present?
+ @collection = Collection.find_by!(name: params[:collection_id]) if params[:collection_id].present?
if params[:tag_id].present?
@tag = Tag.find_by_name(params[:tag_id])
- unless @tag && @tag.is_a?(Tag)
- raise ActiveRecord::RecordNotFound, "Couldn't find tag named '#{params[:tag_id]}'"
- end
+ raise ActiveRecord::RecordNotFound, "Couldn't find tag named '#{params[:tag_id]}'" unless @tag.is_a?(Tag)
+
unless @tag.canonical?
- if @tag.merger.present?
- redirect_to tag_collections_path(@tag.merger) and return
- else
- redirect_to(tag_path(@tag)) && return
- end
+ redirect_path = @tag.merger.present? ? tag_collections_path(@tag.merger) : tag_path(@tag)
+ redirect_to redirect_path and return
end
end
@owner = @user || @work || @collection || @tag
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index 5c4fd240af8..796d2ad1d39 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -28,7 +28,8 @@ def search_header(collection, search, item_name, parent=nil)
when Language
header << ts("in %{language}", language: parent.name)
when Work
- header << ts("including %{work}", work: parent.title)
+ # the rest will also be i18n'd like this with AO3-7357
+ header << t("search_helper.search_header.scope.work", work: parent.title)
end
header << ts("in %{tag_link}", tag_link: link_to_tag_with_text(parent, parent.name)) if parent.is_a?(Tag)
diff --git a/app/models/search/collection_query.rb b/app/models/search/collection_query.rb
index 142f2bf09dd..c9494eb552e 100644
--- a/app/models/search/collection_query.rb
+++ b/app/models/search/collection_query.rb
@@ -49,17 +49,17 @@ def add_owner
owner = options[:parent]
# should maybe be an if statement?
case owner
- when Tag
- options[:filter_ids] ||= []
- options[:filter_ids] << owner.id
- when User
- options[:maintainer_id] = owner.id
- options[:sort_column] = "title.keyword"
- options[:sort_direction] = "asc"
- when Collection
- options[:parent_id] = owner.id
- options[:sort_column] = "title.keyword"
- options[:sort_direction] = "asc"
+ when Tag
+ options[:filter_ids] ||= []
+ options[:filter_ids] << owner.id
+ when User
+ options[:maintainer_id] = owner.id
+ options[:sort_column] = "title.keyword"
+ options[:sort_direction] = "asc"
+ when Collection
+ options[:parent_id] = owner.id
+ options[:sort_column] = "title.keyword"
+ options[:sort_direction] = "asc"
end
end
diff --git a/app/views/collections/_collection_blurb.html.erb b/app/views/collections/_collection_blurb.html.erb
index 81824b6a734..417bed15781 100644
--- a/app/views/collections/_collection_blurb.html.erb
+++ b/app/views/collections/_collection_blurb.html.erb
@@ -17,7 +17,7 @@
<% unless collection.tag_string.blank? %>
<% end %>
diff --git a/app/views/tags/show.html.erb b/app/views/tags/show.html.erb
index 102b8b9f757..0cadfc2916b 100644
--- a/app/views/tags/show.html.erb
+++ b/app/views/tags/show.html.erb
@@ -6,14 +6,14 @@
<% if @tag.canonical || @tag.merger || can_wrangle? %>
<% if @tag.canonical || @tag.merger %>
- - <%= link_to ts("Works"), tag_works_path(@tag) %>
- - <%= link_to ts("Bookmarks"), tag_bookmarks_path(@tag) %>
- - <%= link_to ts("Collections"), tag_collections_path(@tag) %>
+ - <%= link_to t(".navigation.works"), tag_works_path(@tag) %>
+ - <%= link_to t(".navigation.bookmarks"), tag_bookmarks_path(@tag) %>
+ - <%= link_to t(".navigation.collections"), tag_collections_path(@tag) %>
<% end %>
<% if can_wrangle? %>
- - <%= link_to ts("Edit"), edit_tag_path(@tag) %>
+ - <%= link_to t(".navigation.edit"), edit_tag_path(@tag) %>
- <%= tag_comment_link(@tag) %>
- - <%= link_to ts("Troubleshoot"), tag_troubleshooting_path(@tag) %>
+ - <%= link_to t(".navigation.troubleshoot"), tag_troubleshooting_path(@tag) %>
<% end %>
<% end %>
diff --git a/app/views/works/index.html.erb b/app/views/works/index.html.erb
index 56983ac6b53..a5af74ae156 100755
--- a/app/views/works/index.html.erb
+++ b/app/views/works/index.html.erb
@@ -18,15 +18,15 @@
<% if @user %>
<% if @user == current_user %>
- - <%= link_to ts("Edit Works"), show_multiple_user_works_path(@user) %>
+ - <%= link_to t(".navigation.user_edit_works"), show_multiple_user_works_path(@user) %>
<% end %>
- - <%= span_if_current ts("Works in Collections"), collected_user_works_path(@user) %>
- - <%= span_if_current ts("Works"), user_works_path(@user) %>
+ - <%= span_if_current t(".navigation.user_collection_works"), collected_user_works_path(@user) %>
+ - <%= span_if_current t(".navigation.user_works"), user_works_path(@user) %>
<% end %>
<% if @tag && !@collection %>
- - <%= span_if_current ts("Works"), tag_works_path(@tag) %>
- - <%= span_if_current ts("Bookmarks"), tag_bookmarks_path(@tag) %>
- - <%= span_if_current ts("Collections"), tag_collections_path(@tag) %>
+ - <%= span_if_current t(".navigation.tag_works"), tag_works_path(@tag) %>
+ - <%= span_if_current t(".navigation.tag_bookmarks"), tag_bookmarks_path(@tag) %>
+ - <%= span_if_current t(".navigation.tag_collections"), tag_collections_path(@tag) %>
<% end %>
<% if @facets.present? %>
<%# Filters button for narrow screens jumps to filters when JavaScript is disabled and opens filters when JavaScript is enabled %>
diff --git a/config/locales/helpers/en.yml b/config/locales/helpers/en.yml
index 11752c002a0..b3f76133a69 100644
--- a/config/locales/helpers/en.yml
+++ b/config/locales/helpers/en.yml
@@ -49,6 +49,10 @@ en:
qr_code_helper:
qr_code_as_svg:
default_label: QR code
+ search_helper:
+ search_header:
+ scope:
+ work: including %{work}
series_helper:
series_description_html: Part %{index} of %{series_link}
tags_helper:
diff --git a/config/locales/views/en.yml b/config/locales/views/en.yml
index 58391af0232..7bc0fcdbdbe 100644
--- a/config/locales/views/en.yml
+++ b/config/locales/views/en.yml
@@ -817,8 +817,8 @@ en:
label: Multifandom
index:
landmark:
- navigation: Navigation
list_collections: List of Collections
+ navigation: Navigation
navigation:
all_collections: Collections
bookmarks: Bookmarks
@@ -3017,9 +3017,15 @@ en:
more: and more
fandom_relationship_tags: Relationship tags in this fandom
filter_bookmarks: filter bookmarks
- filter_works: filter works
filter_collections: filter collections
+ filter_works: filter works
list_fandom_tags_html: You can also access a list of %{fandom_relationship_tags_link}.
+ navigation:
+ bookmarks: Bookmarks
+ collections: Collections
+ edit: Edit
+ troubleshoot: Troubleshoot
+ works: Works
synonyms: 'Tags with the same meaning:'
wrangle:
manage:
@@ -3339,6 +3345,13 @@ en:
index:
advanced_search: try our advanced search
choose_fandom: choose a fandom
+ navigation:
+ tag_bookmarks: Bookmarks
+ tag_collections: Collections
+ tag_works: Works
+ user_collection_works: Works in Collections
+ user_edit_works: Edit Works
+ user_works: Works
recent_works_html: These are some of the latest works posted to the Archive. To find more works, %{choose_fandom_link} or %{advanced_search_link}.
meta:
original_creators:
diff --git a/features/support/paths.rb b/features/support/paths.rb
index 30f84bfa476..113129643bc 100644
--- a/features/support/paths.rb
+++ b/features/support/paths.rb
@@ -199,7 +199,7 @@ def path_to(page_name)
tag_bookmarks_path(Tag.find_by_name(Regexp.last_match(1)))
when /^the collections "(.*)"$/i
step %{all indexing jobs have been run}
- tag_collections_path(Tag.find_by_name($1))
+ tag_collections_path(Tag.find_by_name(Regexp.last_match(1)))
when /^the bookmarks in collection "(.*)"$/i
step %{all indexing jobs have been run}
collection_bookmarks_path(Collection.find_by(title: $1))
From 5d3ea819dd40a06a18706aa4a2adbd999e4a0226 Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Wed, 15 Apr 2026 05:46:31 +0000
Subject: [PATCH 15/32] AO3-7147 Fix collections index page title's i18n
---
app/controllers/collections_controller.rb | 23 ++++++++++-------------
config/locales/controllers/en.yml | 9 ++++-----
2 files changed, 14 insertions(+), 18 deletions(-)
diff --git a/app/controllers/collections_controller.rb b/app/controllers/collections_controller.rb
index 3a54cc18417..f62b22ee5d9 100644
--- a/app/controllers/collections_controller.rb
+++ b/app/controllers/collections_controller.rb
@@ -37,7 +37,16 @@ def index
options = params[:collection_search].present? ? collection_filter_params : {}
options.merge!(base_options)
- @page_title = index_page_title
+ @page_title = case @owner
+ when Collection
+ t(".subcollection", collection_title: @collection.title)
+ when User
+ t(".user", user_name: @user.login)
+ when Tag
+ t(".tag", tag_name: @tag.name)
+ else
+ t(".general")
+ end
if params[:work_id].present?
@collections = @work.approved_collections
@@ -212,18 +221,6 @@ def load_owner
@owner = @user || @work || @collection || @tag
end
- def index_page_title
- if @collection.present?
- t(".page_title.subcollection", collection_title: @collection.title)
- elsif @user.present?
- t(".page_title.user", user_name: @user.login)
- elsif @tag.present?
- t(".page_title.tag", tag_name: @tag.name)
- else
- t(".page_title.general")
- end
- end
-
private
def collection_filter_params
diff --git a/config/locales/controllers/en.yml b/config/locales/controllers/en.yml
index f8ca11b9e53..62f8bf1f2b1 100644
--- a/config/locales/controllers/en.yml
+++ b/config/locales/controllers/en.yml
@@ -137,11 +137,10 @@ en:
page_title: "%{collection_title} - Profile"
collections:
index:
- page_title:
- general: "Collections"
- subcollection: "%{collection_title} - Subcollections"
- tag: "%{tag_name} - Collections"
- user: "%{user_name} - Collections"
+ general: Collections
+ subcollection: "%{collection_title} - Subcollections"
+ tag: "%{tag_name} - Collections"
+ user: "%{user_name} - Collections"
comments:
check_blocked:
parent: Sorry, you have been blocked by one or more of this work's creators.
From 42b552b7071ae3af6f2373f9a518ac6097b73d92 Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Wed, 20 May 2026 20:18:59 +0000
Subject: [PATCH 16/32] AO3-7144 Un-i18n a search header to unblock AO3-7357
---
app/helpers/search_helper.rb | 3 +--
config/locales/helpers/en.yml | 4 ----
2 files changed, 1 insertion(+), 6 deletions(-)
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index 796d2ad1d39..5c4fd240af8 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -28,8 +28,7 @@ def search_header(collection, search, item_name, parent=nil)
when Language
header << ts("in %{language}", language: parent.name)
when Work
- # the rest will also be i18n'd like this with AO3-7357
- header << t("search_helper.search_header.scope.work", work: parent.title)
+ header << ts("including %{work}", work: parent.title)
end
header << ts("in %{tag_link}", tag_link: link_to_tag_with_text(parent, parent.name)) if parent.is_a?(Tag)
diff --git a/config/locales/helpers/en.yml b/config/locales/helpers/en.yml
index b3f76133a69..11752c002a0 100644
--- a/config/locales/helpers/en.yml
+++ b/config/locales/helpers/en.yml
@@ -49,10 +49,6 @@ en:
qr_code_helper:
qr_code_as_svg:
default_label: QR code
- search_helper:
- search_header:
- scope:
- work: including %{work}
series_helper:
series_description_html: Part %{index} of %{series_link}
tags_helper:
From 08b62efb5349e702df1dd66baaa643b089227bb6 Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Wed, 29 Jul 2026 21:48:11 +0000
Subject: [PATCH 17/32] AO3-7147 Miscellaneous minor fixes per suggestion
---
app/controllers/collections_controller.rb | 64 +++++++++++--------
app/models/search/collection_query.rb | 19 ------
app/views/collection_profile/show.html.erb | 2 +-
.../collections/_collection_blurb.html.erb | 2 +-
app/views/collections/index.html.erb | 4 +-
.../_wrangler_dashboard.html.erb | 2 +-
config/locales/controllers/en.yml | 9 +--
config/routes.rb | 2 +-
features/support/paths.rb | 2 +-
9 files changed, 48 insertions(+), 58 deletions(-)
diff --git a/app/controllers/collections_controller.rb b/app/controllers/collections_controller.rb
index 1580d858653..d620cb87d6f 100644
--- a/app/controllers/collections_controller.rb
+++ b/app/controllers/collections_controller.rb
@@ -40,41 +40,33 @@ def index
@page_subtitle = case @owner
when Collection
- t(".subcollection", collection_title: @collection.title)
+ t(".page_title.subcollection", collection_title: @collection.title)
when User
- t(".user", user_name: @user.login)
+ t(".page_title.user", username: @user.login)
when Tag
- t(".tag", tag_name: @tag.name)
+ t(".page_title.tag", tag_name: @tag.name)
else
- t(".general")
+ t(".page_title.general")
end
-
- if @work.present?
- @collections = @work.approved_collections
- .by_title
- .for_blurb
- .paginate(page: params[:page])
- elsif @user.present?
- # maybe find a way to merge this elsif branch
- # into the @owner.present? one below it later
- @sort_and_filter = true
- @search = CollectionSearchForm.new(options.merge({ maintainer_id: @user.id }))
- @collections = @search.search_results.scope(:for_search)
- flash_search_warnings(@collections)
- elsif @owner.present?
- # include "|| @user.present?" in this one later after deleting above
- @sort_and_filter = @tag.present?
- @search = CollectionSearchForm.new(options.merge(parent: @owner))
- @collections = @search.search_results.scope(:for_search)
- flash_search_warnings(@collections)
- @pagy = pagy_query_result(@collections) if @collections.respond_to?(:total_pages)
+
+ if @owner.present?
+ @sort_and_filter = @user.present? || @tag.present?
+ if @work.present?
+ @collections = @work.approved_collections
+ .by_title
+ .for_blurb
+ .paginate(page: params[:page])
+ else
+ @search = CollectionSearchForm.new(options.merge(parent: @owner))
+ @collections = @search.search_results.scope(:for_search)
+ end
else
@sort_and_filter = true
@search = CollectionSearchForm.new(options)
@collections = @search.search_results.scope(:for_search)
- flash_search_warnings(@collections)
- @pagy = pagy_query_result(@collections) if @collections.respond_to?(:total_pages)
end
+ flash_search_warnings(@collections) if @sort_and_filter
+ @pagy = pagy_query_result(@collections) if @collections.respond_to?(:total_pages)
end
# display challenges that are currently taking signups
@@ -219,8 +211,7 @@ def load_owner
@work = Work.find(params[:work_id]) if params[:work_id].present?
@collection = Collection.find_by!(name: params[:collection_id]) if params[:collection_id].present?
if params[:tag_id].present?
- @tag = Tag.find_by_name(params[:tag_id])
- raise ActiveRecord::RecordNotFound, "Couldn't find tag named '#{params[:tag_id]}'" unless @tag.is_a?(Tag)
+ @tag = Tag.find_by_name!(params[:tag_id])
unless @tag.canonical?
redirect_path = @tag.merger.present? ? tag_collections_path(@tag.merger) : tag_path(@tag)
@@ -230,6 +221,23 @@ def load_owner
@owner = @user || @work || @collection || @tag
end
+ def add_owner
+ owner = options[:parent]
+ case owner
+ when Tag
+ options[:filter_ids] ||= []
+ options[:filter_ids] << owner.id
+ when User
+ options[:maintainer_id] = owner.id
+ options[:sort_column] = "title.keyword"
+ options[:sort_direction] = "asc"
+ when Collection
+ options[:parent_id] = owner.id
+ options[:sort_column] = "title.keyword"
+ options[:sort_direction] = "asc"
+ end
+ end
+
private
def collection_filter_params
diff --git a/app/models/search/collection_query.rb b/app/models/search/collection_query.rb
index caec5814935..cc32818a1ea 100644
--- a/app/models/search/collection_query.rb
+++ b/app/models/search/collection_query.rb
@@ -24,7 +24,6 @@ def parsed_included_tags
# Combine the available filters
def filters
- add_owner
[
multifandom_filter,
signup_open_filter,
@@ -45,24 +44,6 @@ def queries
].flatten.compact
end
- def add_owner
- owner = options[:parent]
- # should maybe be an if statement?
- case owner
- when Tag
- options[:filter_ids] ||= []
- options[:filter_ids] << owner.id
- when User
- options[:maintainer_id] = owner.id
- options[:sort_column] = "title.keyword"
- options[:sort_direction] = "asc"
- when Collection
- options[:parent_id] = owner.id
- options[:sort_column] = "title.keyword"
- options[:sort_direction] = "asc"
- end
- end
-
####################
# FILTERS
####################
diff --git a/app/views/collection_profile/show.html.erb b/app/views/collection_profile/show.html.erb
index 228f8d05fc8..d51bc95bbc0 100644
--- a/app/views/collection_profile/show.html.erb
+++ b/app/views/collection_profile/show.html.erb
@@ -19,7 +19,7 @@
-
diff --git a/app/views/collections/_collection_blurb.html.erb b/app/views/collections/_collection_blurb.html.erb
index 483c00f091b..f15a94724d9 100644
--- a/app/views/collections/_collection_blurb.html.erb
+++ b/app/views/collections/_collection_blurb.html.erb
@@ -17,7 +17,7 @@
<% unless collection.tag_string.blank? %>
<% end %>
diff --git a/app/views/collections/index.html.erb b/app/views/collections/index.html.erb
index 322a001d821..af9a37d8206 100755
--- a/app/views/collections/index.html.erb
+++ b/app/views/collections/index.html.erb
@@ -44,7 +44,7 @@
<% unless @collections.blank? %>
- <%= will_paginate @collections %>
+ <%= pagy_nav @pagy %>
<%= t(".landmark.list_collections") %>
@@ -62,5 +62,5 @@
<% end %>
<% unless @collections.blank? %>
- <%= will_paginate @collections %>
+ <%= pagy_nav @pagy %>
<% end %>
diff --git a/app/views/tag_wranglings/_wrangler_dashboard.html.erb b/app/views/tag_wranglings/_wrangler_dashboard.html.erb
index 3f16d4d05d5..183989d04f9 100644
--- a/app/views/tag_wranglings/_wrangler_dashboard.html.erb
+++ b/app/views/tag_wranglings/_wrangler_dashboard.html.erb
@@ -33,7 +33,7 @@
<% elsif key == "Collections" %>
-
<%= span_if_current t(".use_type_and_count", use_type: t(".use_type.collections"), count: @counts[key]),
- { controller: :collections, action: :index, tag_id: @tag } %>
+ tag_collections_path %>
<% else %>
-
diff --git a/config/locales/controllers/en.yml b/config/locales/controllers/en.yml
index 858e8731507..761b1e1ddaa 100644
--- a/config/locales/controllers/en.yml
+++ b/config/locales/controllers/en.yml
@@ -170,10 +170,11 @@ en:
page_title: "%{collection_title} - Profile"
collections:
index:
- general: Collections
- subcollection: "%{collection_title} - Subcollections"
- tag: "%{tag_name} - Collections"
- user: "%{username} - Collections"
+ page_title:
+ general: Collections
+ subcollection: "%{collection_title} - Subcollections"
+ tag: "%{tag_name} - Collections"
+ user: "%{username} - Collections"
comments:
check_blocked:
parent: Sorry, you have been blocked by one or more of this work's creators.
diff --git a/config/routes.rb b/config/routes.rb
index 336efb56264..0fa28bdeb0a 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -132,7 +132,7 @@
end
resources :works
resources :bookmarks
- resources :collections
+ resources :collections, only: [:index]
resources :comments
resource :troubleshooting, controller: :troubleshooting, only: [:show, :update]
end
diff --git a/features/support/paths.rb b/features/support/paths.rb
index 1a994a8cf4b..7da0b1f6639 100644
--- a/features/support/paths.rb
+++ b/features/support/paths.rb
@@ -209,7 +209,7 @@ def path_to(page_name)
when /^the bookmarks (?:tagged|page for the tag) "(.*)"$/i
step %{all indexing jobs have been run}
tag_bookmarks_path(Tag.find_by_name(Regexp.last_match(1)))
- when /^the collections "(.*)"$/i
+ when /^the collections tagged "(.*)"$/i
step %{all indexing jobs have been run}
tag_collections_path(Tag.find_by_name(Regexp.last_match(1)))
when /^the bookmarks in collection "(.*)"$/i
From 3f09da62818516cf7bd63b17c45bc6e1f913b882 Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Sat, 1 Aug 2026 03:28:34 +0000
Subject: [PATCH 18/32] AO3-7144-7147 Miscellaneous functional fixes
---
app/controllers/collections_controller.rb | 30 ++++++++++-----------
app/helpers/search_helper.rb | 5 +---
app/models/search/collection_search_form.rb | 3 +--
app/views/collections/_filters.html.erb | 7 +----
app/views/collections/index.html.erb | 4 ++-
5 files changed, 21 insertions(+), 28 deletions(-)
diff --git a/app/controllers/collections_controller.rb b/app/controllers/collections_controller.rb
index d620cb87d6f..4a292716114 100644
--- a/app/controllers/collections_controller.rb
+++ b/app/controllers/collections_controller.rb
@@ -48,16 +48,22 @@ def index
else
t(".page_title.general")
end
-
+
if @owner.present?
- @sort_and_filter = @user.present? || @tag.present?
if @work.present?
+ @sort_and_filter = false
@collections = @work.approved_collections
.by_title
.for_blurb
.paginate(page: params[:page])
- else
- @search = CollectionSearchForm.new(options.merge(parent: @owner))
+ elsif @collection.present?
+ @sort_and_filter = false
+ @search = CollectionSearchForm.new({ parent_id: @collection.id, sort_column: "title.keyword" }.merge(page: params[:page]))
+ @collections = @search.search_results.scope(:for_search)
+ elsif @user.present? || @tag.present?
+ @sort_and_filter = true
+ add_owner options
+ @search = CollectionSearchForm.new(options)
@collections = @search.search_results.scope(:for_search)
end
else
@@ -65,6 +71,7 @@ def index
@search = CollectionSearchForm.new(options)
@collections = @search.search_results.scope(:for_search)
end
+
flash_search_warnings(@collections) if @sort_and_filter
@pagy = pagy_query_result(@collections) if @collections.respond_to?(:total_pages)
end
@@ -221,20 +228,13 @@ def load_owner
@owner = @user || @work || @collection || @tag
end
- def add_owner
- owner = options[:parent]
- case owner
+ def add_owner(options)
+ case @owner
when Tag
options[:filter_ids] ||= []
- options[:filter_ids] << owner.id
+ options[:filter_ids] << @owner.id
when User
- options[:maintainer_id] = owner.id
- options[:sort_column] = "title.keyword"
- options[:sort_direction] = "asc"
- when Collection
- options[:parent_id] = owner.id
- options[:sort_column] = "title.keyword"
- options[:sort_direction] = "asc"
+ options[:maintainer_id] = @owner.id
end
end
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index 17dcfe90e40..2e8b61dbbbb 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -26,8 +26,6 @@ def search_header(collection, search, item_name, parent = nil)
header << ts("by %{username}", username: parent.login)
when Language
header << ts("in %{language}", language: parent.name)
- # when Work
- # header << ts("including %{work}", work: parent.title)
end
header << ts("in %{tag_link}", tag_link: link_to_tag_with_text(parent, parent.name)) if parent.is_a?(Tag)
@@ -67,8 +65,7 @@ def collections_original_path
url_for(
controller: :collections,
action: :index,
- only_path: true,
- **params.slice(:tag_id, :collection_id, :user_id, :work_id).permit!
+ only_path: true
)
end
end
diff --git a/app/models/search/collection_search_form.rb b/app/models/search/collection_search_form.rb
index cf93ac5f92b..650ada01605 100644
--- a/app/models/search/collection_search_form.rb
+++ b/app/models/search/collection_search_form.rb
@@ -7,11 +7,10 @@ class CollectionSearchForm
challenge_type
closed
maintainer_id
- filter_ids
- parent_id
moderated
multifandom
page
+ parent_id
per_page
signup_open
sort_column
diff --git a/app/views/collections/_filters.html.erb b/app/views/collections/_filters.html.erb
index d4558ec0acd..c9c54497740 100644
--- a/app/views/collections/_filters.html.erb
+++ b/app/views/collections/_filters.html.erb
@@ -1,5 +1,5 @@
<%= form_for @search, as: :collection_search,
- url: (@user ? user_collections_path(@user) : collections_path),
+ url: (@user ? user_collections_path(@user) : (@tag? tag_collections_path(@tag) : collections_path)),
html: {
method: :get,
class: "narrow-hidden filters",
@@ -141,11 +141,6 @@
-
- <%= hidden_field_tag("collection_id", @collection.id) if @collection %>
- <%= hidden_field_tag("tag_id", @tag.to_param) if @tag %>
- <%= hidden_field_tag("user_id", @user.login) if @user %>
-
<% end %>
<% # On narrow screens, link jumps to top of index when JavaScript is disabled and closes filters when JavaScript is enabled %>
diff --git a/app/views/collections/index.html.erb b/app/views/collections/index.html.erb
index af9a37d8206..f5fb062f519 100755
--- a/app/views/collections/index.html.erb
+++ b/app/views/collections/index.html.erb
@@ -1,9 +1,11 @@
- <% if @user || @tag || @work %>
+ <% if @user || @tag %>
<%= search_header(@collections, @query, t(".page_heading.collection"), @owner) %>
<% elsif @collection %>
<%= search_header(@collections, @query, t(".page_heading.subcollection"), @owner) %>
+ <% elsif @work %>
+ <%= t(".page_heading.collections_including", work: @work.title) %>
<% else %>
<%= t(".page_heading.collections_in_the", collections: search_header(@collections, @query, t(".page_heading.collection"), @owner), archive: ArchiveConfig.APP_NAME) %>
<% end %>
From 868565eb232b87bc5e294b2b7ff81f4f6947dc64 Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Sat, 1 Aug 2026 06:18:04 +0000
Subject: [PATCH 19/32] AO3-7147 Separate new tag page search tests from
regular search tests
---
app/views/tags/show.html.erb | 3 +-
config/locales/views/en.yml | 3 +-
.../collections/collection_browse.feature | 14 +-
.../collections/collection_taglisting.feature | 145 +++++++++---------
features/step_definitions/collection_steps.rb | 36 ++++-
5 files changed, 105 insertions(+), 96 deletions(-)
diff --git a/app/views/tags/show.html.erb b/app/views/tags/show.html.erb
index 0cadfc2916b..5a2505607c4 100644
--- a/app/views/tags/show.html.erb
+++ b/app/views/tags/show.html.erb
@@ -28,8 +28,7 @@
<%= t(".canonical_html",
canonical_tag_link: link_to(t(".canonical_tag"), archive_faq_path("glossary", anchor: "canonicaldef")),
filter_works_link: link_to(t(".filter_works"), tag_works_path(@tag)),
- filter_bookmarks_link: link_to(t(".filter_bookmarks"), tag_bookmarks_path(@tag)),
- filter_collections_link: link_to(t(".filter_collections"), tag_collections_path(@tag))) %>
+ filter_bookmarks_link: link_to(t(".filter_bookmarks"), tag_bookmarks_path(@tag))) %>
<% if @tag.is_a?(Fandom) %>
<%= t(".list_fandom_tags_html", fandom_relationship_tags_link: link_to(t(".fandom_relationship_tags"), fandom_path(@tag))) %>
<% end %>
diff --git a/config/locales/views/en.yml b/config/locales/views/en.yml
index 0384df34c28..fb4e8d18486 100644
--- a/config/locales/views/en.yml
+++ b/config/locales/views/en.yml
@@ -3109,14 +3109,13 @@ en:
type: Type
wrangling_status: Wrangling status
show:
- canonical_html: It's a %{canonical_tag_link}. You can use it to %{filter_works_link} and to %{filter_bookmarks_link}, as well as %{filter_collections_link}.
+ canonical_html: It's a %{canonical_tag_link}. You can use it to %{filter_works_link} and to %{filter_bookmarks_link}.
canonical_tag: canonical tag
children:
heading: 'Child tags (displaying the first %{count} of each type):'
more: and more
fandom_relationship_tags: Relationship tags in this fandom
filter_bookmarks: filter bookmarks
- filter_collections: filter collections
filter_works: filter works
list_fandom_tags_html: You can also access a list of %{fandom_relationship_tags_link}.
navigation:
diff --git a/features/collections/collection_browse.feature b/features/collections/collection_browse.feature
index 9e976d5aeef..6d3d64d39fa 100644
--- a/features/collections/collection_browse.feature
+++ b/features/collections/collection_browse.feature
@@ -179,7 +179,7 @@ Feature: Collection
And I should not see "Some Other Collection"
And I should not see "Surprise Presents"
- Scenario: Filter collections by canonicals, synonyms, noncanonicals, and non-existent collection tags
+ Scenario: Filter collections by non-canonical and non-existent collection tags
Given a set of collections for searching
When I go to the collections page
@@ -187,8 +187,8 @@ Feature: Collection
And I press "Sort and Filter"
Then I should see "Some Test Collection"
And I should see "Some Other Collection"
- And I should see "Surprise Presents"
But I should not see "Another Plain Collection"
+ And I should not see "Surprise Presents"
And I should not see "Another Gift Swap"
And I should not see "On Demand"
When I fill in "collection_search_tag" with "The Best Tag,The Better Tag"
@@ -204,15 +204,7 @@ Feature: Collection
Then I should see "Some Test Collection"
And I should see "Some Other Collection"
And I should see "Another Plain Collection"
- And I should see "Surprise Presents"
- And I should not see "Another Gift Swap"
- And I should not see "On Demand"
- When I fill in "collection_search_tag" with "TBT"
- And I press "Sort and Filter"
- Then I should see "Surprise Presents"
- But I should not see "Some Test Collection"
- And I should not see "Some Other Collection"
- And I should not see "Another Plain Collection"
+ But I should not see "Surprise Presents"
And I should not see "Another Gift Swap"
And I should not see "On Demand"
diff --git a/features/collections/collection_taglisting.feature b/features/collections/collection_taglisting.feature
index 2b12b20a7e5..c13eabcd2cd 100644
--- a/features/collections/collection_taglisting.feature
+++ b/features/collections/collection_taglisting.feature
@@ -5,116 +5,109 @@ Feature: Collection
I want to locate and browse through tag collection listings
Scenario: Tags and synonyms of the tag show up in the tag's collection listing
- Given a set of collections for searching
+ Given a set of collections for tag page searching
When I go to the collections page
- And I follow "The Best Tag"
- Then I should see the page title "The Best Tag - Collections"
- And I should see "The Best Tag" within "h2.heading"
+ And I follow "My Beautiful Canonical Tag"
+ Then I should see the page title "My Beautiful Canonical Tag - Collections"
+ And I should see "My Beautiful Canonical Tag" within "h2.heading"
And I should see "3 Collections" within "h2.heading"
And I should not see "Example Archive" within "h2.heading"
- And I should see "Some Test Collection"
- And I should see "Some Other Collection"
- And I should see "Surprise Presents"
- But I should not see "Another Plain Collection"
- And I should not see "Another Gift Swap"
- And I should not see "On Demand"
+ And I should see "Beautiful Tag Test Collection"
+ And I should see "Multiple Tag Test Collection"
+ And I should see "Gorgeous Tag Test Collection"
+ But I should not see "Noncanonical Tag Test Collection"
+
+ Scenario: Clicking on a synonymous tag on a collection also brings you to the canonical tag's collection page
+ Given a set of collections for tag page searching
+ When I go to the collections page
+ And I follow "My Gorgeous Synonymous Tag"
+ Then I should see the page title "My Beautiful Canonical Tag - Collections"
+ And I should see "My Beautiful Canonical Tag" within "h2.heading"
+ And I should see "3 Collections" within "h2.heading"
+ And I should see "Beautiful Tag Test Collection"
+ And I should see "Multiple Tag Test Collection"
+ And I should see "Gorgeous Tag Test Collection"
+ But I should not see "Noncanonical Tag Test Collection"
Scenario: We can further filter a tag's collection listing with collection_search_tag
- Given a set of collections for searching
+ Given a set of collections for tag page searching
When I go to the collections page
- And I follow "The Best Tag"
- Then I should see "The Best Tag" within "h2.heading"
- And I should see "3 Collections" within "h2.heading"
- And I should not see "Example Archive" within "h2.heading"
- When I fill in "collection_search_tag" with "The Better Tag"
+ And I follow "My Beautiful Canonical Tag"
+ And I fill in "collection_search_tag" with "a noncanonical tag"
And I press "Sort and Filter"
- Then I should see "The Best Tag" within "h2.heading"
+ Then I should see "My Beautiful Canonical Tag" within "h2.heading"
And I should see "1 Collection" within "h2.heading"
- And I should not see "Example Archive" within "h2.heading"
- And I should see "Some Test Collection"
- But I should not see "Some Other Collection"
- And I should not see "Surprise Presents"
- And I should not see "Another Plain Collection"
- And I should not see "Another Gift Swap"
- And I should not see "On Demand"
+ And I should see "Multiple Tag Test Collection"
+ But I should not see "Beautiful Tag Test Collection"
+ And I should not see "Noncanonical Tag Test Collection"
+ And I should not see "Gorgeous Tag Test Collection"
- Scenario: We can filter a tag's collection listing with radio buttons
- Given a set of collections for searching
+ Scenario: We can further filter a tag's collection listing with radio buttons
+ Given a set of collections for tag page searching
When I go to the collections page
- And I follow "The Best Tag"
- Then I should see "The Best Tag" within "h2.heading"
- And I should see "3 Collections" within "h2.heading"
- And I should not see "Example Archive" within "h2.heading"
- When I choose "collection_search_challenge_type_giftexchange"
+ And I follow "My Beautiful Canonical Tag"
+ And I choose "collection_search_challenge_type_giftexchange"
And I press "Sort and Filter"
- Then I should see "The Best Tag" within "h2.heading"
+ Then I should see "My Beautiful Canonical Tag" within "h2.heading"
And I should see "1 Collection" within "h2.heading"
- And I should not see "Example Archive" within "h2.heading"
- And I should see "Surprise Presents"
- And I should not see "Some Test Collection"
- But I should not see "Some Other Collection"
- And I should not see "Another Plain Collection"
- And I should not see "Another Gift Swap"
- And I should not see "On Demand"
+ And I should see "Gorgeous Tag Test Collection"
+ But I should not see "Beautiful Tag Test Collection"
+ And I should not see "Multiple Tag Test Collection"
+ And I should not see "Noncanonical Tag Test Collection"
+
+ Scenario: Clearing filters brings us back to the tag's collection listing
+ Given a set of collections for tag page searching
+ When I go to the collections page
+ And I follow "My Beautiful Canonical Tag"
+ And I choose "collection_search_challenge_type_giftexchange"
+ And I press "Sort and Filter"
+ Then I should see "My Beautiful Canonical Tag" within "h2.heading"
+ And I should see "1 Collection" within "h2.heading"
+ When I follow "Clear Filters"
+ Then I should see "My Beautiful Canonical Tag" within "h2.heading"
+ And I should see "3 Collections" within "h2.heading"
Scenario: We can find collection listings for a tag through a collection profile
- Given a set of collections for searching
- When I go to "Some Test Collection" collection's page
+ Given a set of collections for tag page searching
+ When I go to "Beautiful Tag Test Collection" collection's page
And I follow "Profile"
- And I follow "The Best Tag" within ".tags"
- Then I should see "The Best Tag" within "h2.heading"
- And I should see "3 Collections" within "h2.heading"
- And I should not see "Example Archive" within "h2.heading"
-
- Scenario: We can find collection listings for a tag through the tag profile
- Given a set of collections for searching
- When I view the tag "The Best Tag"
- And I follow "filter collections"
- Then I should see "The Best Tag" within "h2.heading"
+ And I follow "My Beautiful Canonical Tag" within ".tags"
+ Then I should see "My Beautiful Canonical Tag" within "h2.heading"
And I should see "3 Collections" within "h2.heading"
- And I should not see "Example Archive" within "h2.heading"
Scenario: We can find collection listings for a tag through the buttons at the top of the tag profile and its works/bookmarks pages
- Given a set of collections for searching
- When I view the tag "The Best Tag"
+ Given a set of collections for tag page searching
+ When I view the tag "My Beautiful Canonical Tag"
And I follow "Collections" within ".primary.header.module"
- Then I should see "The Best Tag" within "h2.heading"
+ Then I should see "My Beautiful Canonical Tag" within "h2.heading"
And I should see "3 Collections" within "h2.heading"
- And I should not see "Example Archive" within "h2.heading"
When I follow "Works" within "#main"
- Then I should see "The Best Tag" within "h2.heading"
+ Then I should see "My Beautiful Canonical Tag" within "h2.heading"
And I should see "Works" within "h2.heading"
- And I should not see "Example Archive" within "h2.heading"
When I follow "Collections" within "#main"
- Then I should see "The Best Tag" within "h2.heading"
+ Then I should see "My Beautiful Canonical Tag" within "h2.heading"
And I should see "3 Collections" within "h2.heading"
- And I should not see "Example Archive" within "h2.heading"
When I follow "Bookmarks" within "#main"
- Then I should see "The Best Tag" within "h2.heading"
+ Then I should see "My Beautiful Canonical Tag" within "h2.heading"
And I should see "Bookmarked Items" within "h2.heading"
- And I should not see "Example Archive" within "h2.heading"
When I follow "Collections" within "#main"
- Then I should see "The Best Tag" within "h2.heading"
+ Then I should see "My Beautiful Canonical Tag" within "h2.heading"
And I should see "3 Collections" within "h2.heading"
- And I should not see "Example Archive" within "h2.heading"
Scenario: A tag's collection listings should update when a collection's tags are edited
- Given a set of collections for searching
- When I am logged in as the owner of "Some Other Collection"
- And I go to "Some Other Collection" collection's page
+ Given a set of collections for tag page searching
+ When I am logged in as the owner of "Beautiful Tag Test Collection"
+ And I go to "Beautiful Tag Test Collection" collection's page
And I follow "Profile"
And I follow "Collection Settings"
And I fill in "Collection Tags" with ""
And I press "Update"
And all indexing jobs have been run
- And I view the tag "The Best Tag"
+ And I view the tag "My Beautiful Canonical Tag"
And I follow "Collections" within ".primary.header.module"
- Then I should see "The Best Tag" within "h2.heading"
+ Then I should see "My Beautiful Canonical Tag" within "h2.heading"
And I should see "2 Collections" within "h2.heading"
- And I should not see "Example Archive" within "h2.heading"
- And I should see "Some Test Collection"
- And I should see "Surprise Presents"
- But I should not see "Some Other Collection"
- And I should not see "Another Plain Collection"
- And I should not see "Another Gift Swap"
- And I should not see "On Demand"
\ No newline at end of file
+ And I should see "Multiple Tag Test Collection"
+ And I should see "Gorgeous Tag Test Collection"
+ But I should not see "Beautiful Tag Test Collection"
+ And I should not see "Noncanonical Tag Test Collection"
\ No newline at end of file
diff --git a/features/step_definitions/collection_steps.rb b/features/step_definitions/collection_steps.rb
index 48b00157b3b..47a696cc09d 100644
--- a/features/step_definitions/collection_steps.rb
+++ b/features/step_definitions/collection_steps.rb
@@ -143,11 +143,6 @@
end
Given "a set of collections for searching" do
- thebest = Fandom.where(name: "The Best Tag", canonical: true).first_or_create
- # thebetter = Fandom.where(name: "The Better Tag", canonical: true).first_or_create
- tbt = Fandom.find_or_create_by(name: "TBT")
- tbt.reload.merger = thebest
- tbt.save
profile = CollectionProfile.create!(faq: "- What is this test thing?
- It's a test collection
",
intro: "Welcome to the test collection",
rules: "Be nice to testers")
@@ -185,6 +180,37 @@
step %{all indexing jobs have been run}
end
+Given "a set of collections for tag page searching" do
+ beautiful = Fandom.where(name: "My Beautiful Canonical Tag", canonical: true).first_or_create
+ gorgeous = Fandom.find_or_create_by(name: "My Gorgeous Synonymous Tag")
+ gorgeous.reload.merger = beautiful
+ gorgeous.save
+ profile = CollectionProfile.create!(faq: "FAQ goes here",
+ intro: "Intro goes here",
+ rules: "Rules go here")
+ FactoryBot.create(:collection,
+ name: "btagtest",
+ title: "Beautiful Tag Test Collection",
+ tag_string: "My Beautiful Canonical Tag",
+ collection_profile: profile)
+ FactoryBot.create(:collection,
+ name: "bntagtest",
+ title: "Multiple Tag Test Collection",
+ tag_string: "My Beautiful Canonical Tag, a noncanonical tag")
+ FactoryBot.create(:collection,
+ name: "ntagtest",
+ title: "Noncanonical Tag Test Collection",
+ tag_string: "a noncanonical tag",
+ challenge: FactoryBot.create(:gift_exchange))
+ FactoryBot.create(:collection,
+ name: "gtagtest",
+ title: "Gorgeous Tag Test Collection",
+ tag_string: "My Gorgeous Synonymous Tag",
+ challenge: FactoryBot.create(:gift_exchange))
+
+ step %{all indexing jobs have been run}
+end
+
### WHEN
When /^I set up (?:a|the) collection "([^"]*)"(?: with name "([^"]*)")?$/ do |title, name|
From 535c031d285d20fbc6aa5390261e72d8082a1509 Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Sat, 1 Aug 2026 18:42:25 +0000
Subject: [PATCH 20/32] AO3-7144-7147 Minor linter fixes
---
app/views/collections/_filters.html.erb | 8 +++++++-
config/locales/views/en.yml | 1 -
features/collections/collection_browse.feature | 2 +-
features/collections/collection_navigation.feature | 2 +-
4 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/app/views/collections/_filters.html.erb b/app/views/collections/_filters.html.erb
index c9c54497740..10809b5d523 100644
--- a/app/views/collections/_filters.html.erb
+++ b/app/views/collections/_filters.html.erb
@@ -1,5 +1,11 @@
<%= form_for @search, as: :collection_search,
- url: (@user ? user_collections_path(@user) : (@tag? tag_collections_path(@tag) : collections_path)),
+ url: (if @user
+ user_collections_path(@user)
+ elsif @tag
+ tag_collections_path(@tag)
+ else
+ collections_path
+ end),
html: {
method: :get,
class: "narrow-hidden filters",
diff --git a/config/locales/views/en.yml b/config/locales/views/en.yml
index fb4e8d18486..82b8033b730 100644
--- a/config/locales/views/en.yml
+++ b/config/locales/views/en.yml
@@ -889,7 +889,6 @@ en:
collections_in_the: "%{collections} in the %{archive}"
collections_including: Collections including %{work}
subcollection: Subcollection
- users_collections: "%{user}'s Collections"
sidebar:
bookmarks: Bookmarked Items (%{count})
challenge_settings: Challenge Settings
diff --git a/features/collections/collection_browse.feature b/features/collections/collection_browse.feature
index 6d3d64d39fa..d93dde4b427 100644
--- a/features/collections/collection_browse.feature
+++ b/features/collections/collection_browse.feature
@@ -316,7 +316,7 @@ Feature: Collection
And the 2nd collection result should contain "The Hobbit"
When I fill in "Filter by title" with "Not Mine!"
And I press "Sort and Filter"
- Then I should see "Sorry, there were no collections found."
+ Then I should see "0 Collections"
Scenario: Default sorting is different from collections page and user collections page
diff --git a/features/collections/collection_navigation.feature b/features/collections/collection_navigation.feature
index 1d6822c4e5c..aaa4d01b27b 100644
--- a/features/collections/collection_navigation.feature
+++ b/features/collections/collection_navigation.feature
@@ -33,7 +33,7 @@ Feature: Basic collection navigation
And I should see "Maintainers: mod"
When I follow "Subcollections (0)"
Then I should see "Subcollections in My Collection"
- And I should see "Sorry, there were no collections found."
+ And I should see "0 Collections"
When I follow "Fandoms (1)"
Then I should see "New Fandom (1)"
When I follow "Works (1)"
From d6d0414d670d79e1249f3822d98f539f416edfea Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Sat, 1 Aug 2026 19:57:27 +0000
Subject: [PATCH 21/32] AO3-7147 Fix wrangler dashboard link
---
app/views/tag_wranglings/_wrangler_dashboard.html.erb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/views/tag_wranglings/_wrangler_dashboard.html.erb b/app/views/tag_wranglings/_wrangler_dashboard.html.erb
index 183989d04f9..44321d7af8f 100644
--- a/app/views/tag_wranglings/_wrangler_dashboard.html.erb
+++ b/app/views/tag_wranglings/_wrangler_dashboard.html.erb
@@ -33,7 +33,7 @@
<% elsif key == "Collections" %>
-
<%= span_if_current t(".use_type_and_count", use_type: t(".use_type.collections"), count: @counts[key]),
- tag_collections_path %>
+ tag_collections_path(@tag) %>
<% else %>
-
From 36e3bd2395c92dca2a315b723c4b36bcd85fe6d8 Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Sat, 1 Aug 2026 21:10:34 +0000
Subject: [PATCH 22/32] AO3-7144-7147 More minor linter fixes
---
app/views/collections/index.html.erb | 4 ++--
features/collections/collection_navigation.feature | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/app/views/collections/index.html.erb b/app/views/collections/index.html.erb
index f5fb062f519..1a33e7cecc4 100755
--- a/app/views/collections/index.html.erb
+++ b/app/views/collections/index.html.erb
@@ -20,7 +20,7 @@
- <%= span_if_current t(".navigation.bookmarks"), tag_bookmarks_path(@tag) %>
- <%= span_if_current t(".navigation.collections"), tag_collections_path(@tag) %>
<% end %>
- <% # Collections and Open Challenges links unless a logged in user viewing own collections page %>
+ <%# Collections and Open Challenges links unless a logged in user viewing own collections page %>
<% unless @tag || (logged_in? && @user && @user == current_user) %>
- <%= span_if_current t(".navigation.all_collections"), collections_path %>
- <%= link_to t(".navigation.open_challenges"), list_challenges_collections_path %>
@@ -39,7 +39,7 @@
<% end %>
<% end %>
<% if @sort_and_filter %>
- <% # Filters button for narrow screens jumps to filters when JavaScript is disabled and opens filters when JavaScript is enabled %>
+ <%# Filters button for narrow screens jumps to filters when JavaScript is disabled and opens filters when JavaScript is enabled %>
- <%= t(".navigation.filters") %>
<% end %>
diff --git a/features/collections/collection_navigation.feature b/features/collections/collection_navigation.feature
index aaa4d01b27b..7ccf2c59281 100644
--- a/features/collections/collection_navigation.feature
+++ b/features/collections/collection_navigation.feature
@@ -33,7 +33,7 @@ Feature: Basic collection navigation
And I should see "Maintainers: mod"
When I follow "Subcollections (0)"
Then I should see "Subcollections in My Collection"
- And I should see "0 Collections"
+ And I should see "0 Subcollections"
When I follow "Fandoms (1)"
Then I should see "New Fandom (1)"
When I follow "Works (1)"
From 6d3780b39ca5bbf63a4bec2132cbdaa6664efbde Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Sat, 1 Aug 2026 21:45:08 +0000
Subject: [PATCH 23/32] AO3-7144-7147 Fix permissions for collections
controller
---
app/controllers/collections_controller.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/controllers/collections_controller.rb b/app/controllers/collections_controller.rb
index 4a292716114..6e7d0e9d946 100644
--- a/app/controllers/collections_controller.rb
+++ b/app/controllers/collections_controller.rb
@@ -1,6 +1,6 @@
class CollectionsController < ApplicationController
before_action :load_owner, only: [:index]
- before_action :users_only, only: [:new, :edit, :create, :update]
+ before_action :users_only, only: [:new, :create]
before_action :load_collection_from_id, only: [:show, :edit, :update, :destroy, :confirm_delete]
before_action :collection_owners_or_privileged_admins_only, only: [:edit]
before_action :collection_owners_only, only: [:update, :destroy, :confirm_delete]
From 2958a17d94aaaef5bcebd716c1481520b66fbd8d Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Sat, 1 Aug 2026 22:28:09 +0000
Subject: [PATCH 24/32] AO3-7144-7147 Fix page subtitle test + minor cleanup
---
app/controllers/collections_controller.rb | 4 ++--
features/step_definitions/collection_steps.rb | 3 +--
spec/controllers/collections_controller_spec.rb | 4 ++--
3 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/app/controllers/collections_controller.rb b/app/controllers/collections_controller.rb
index 6e7d0e9d946..f8d04d07aeb 100644
--- a/app/controllers/collections_controller.rb
+++ b/app/controllers/collections_controller.rb
@@ -55,10 +55,10 @@ def index
@collections = @work.approved_collections
.by_title
.for_blurb
- .paginate(page: params[:page])
+ .paginate(base_options)
elsif @collection.present?
@sort_and_filter = false
- @search = CollectionSearchForm.new({ parent_id: @collection.id, sort_column: "title.keyword" }.merge(page: params[:page]))
+ @search = CollectionSearchForm.new({ parent_id: @collection.id, sort_column: "title.keyword" }.merge(base_options))
@collections = @search.search_results.scope(:for_search)
elsif @user.present? || @tag.present?
@sort_and_filter = true
diff --git a/features/step_definitions/collection_steps.rb b/features/step_definitions/collection_steps.rb
index 47a696cc09d..90ee86726e2 100644
--- a/features/step_definitions/collection_steps.rb
+++ b/features/step_definitions/collection_steps.rb
@@ -164,7 +164,6 @@
:moderated,
name: "surprisetest",
title: "Surprise Presents",
- tag_string: "TBT",
challenge: FactoryBot.create(:gift_exchange))
FactoryBot.create(:collection,
name: "swaptest",
@@ -194,7 +193,7 @@
tag_string: "My Beautiful Canonical Tag",
collection_profile: profile)
FactoryBot.create(:collection,
- name: "bntagtest",
+ name: "mtagtest",
title: "Multiple Tag Test Collection",
tag_string: "My Beautiful Canonical Tag, a noncanonical tag")
FactoryBot.create(:collection,
diff --git a/spec/controllers/collections_controller_spec.rb b/spec/controllers/collections_controller_spec.rb
index 15cbd0ab070..a2ba151b757 100644
--- a/spec/controllers/collections_controller_spec.rb
+++ b/spec/controllers/collections_controller_spec.rb
@@ -46,9 +46,9 @@
run_all_indexing_jobs
end
- it "assigns title with collection title and subcollections" do
+ it "assigns subtitle with collection title and subcollections" do
get :index, params: { collection_id: gift_exchange_collection.name }
- expect(assigns[:page_title]).to eq("#{gift_exchange_collection.title} - Subcollections")
+ expect(assigns[:page_subtitle]).to eq("#{gift_exchange_collection.title} - Subcollections")
end
context "collections index" do
From 89092e2ad255c67e135b0500500b6055c02ded59 Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Sat, 3 Oct 2026 05:14:00 +0000
Subject: [PATCH 25/32] AO3-7147 More miscellaneous fixes
---
app/controllers/collections_controller.rb | 3 +--
app/views/collections/index.html.erb | 2 +-
.../collections/collection_taglisting.feature | 15 +++++++--------
3 files changed, 9 insertions(+), 11 deletions(-)
diff --git a/app/controllers/collections_controller.rb b/app/controllers/collections_controller.rb
index f8d04d07aeb..77a7f3e6a65 100644
--- a/app/controllers/collections_controller.rb
+++ b/app/controllers/collections_controller.rb
@@ -55,7 +55,6 @@ def index
@collections = @work.approved_collections
.by_title
.for_blurb
- .paginate(base_options)
elsif @collection.present?
@sort_and_filter = false
@search = CollectionSearchForm.new({ parent_id: @collection.id, sort_column: "title.keyword" }.merge(base_options))
@@ -72,7 +71,7 @@ def index
@collections = @search.search_results.scope(:for_search)
end
- flash_search_warnings(@collections) if @sort_and_filter
+ flash_search_warnings(@collections) if !@work.present?
@pagy = pagy_query_result(@collections) if @collections.respond_to?(:total_pages)
end
diff --git a/app/views/collections/index.html.erb b/app/views/collections/index.html.erb
index 1a33e7cecc4..d33ce36b1e7 100755
--- a/app/views/collections/index.html.erb
+++ b/app/views/collections/index.html.erb
@@ -15,7 +15,7 @@
<%= t(".landmark.navigation") %>
- <% if @tag && !@collection %>
+ <% if @tag %>
- <%= span_if_current t(".navigation.works"), tag_works_path(@tag) %>
- <%= span_if_current t(".navigation.bookmarks"), tag_bookmarks_path(@tag) %>
- <%= span_if_current t(".navigation.collections"), tag_collections_path(@tag) %>
diff --git a/features/collections/collection_taglisting.feature b/features/collections/collection_taglisting.feature
index c13eabcd2cd..37ba4158096 100644
--- a/features/collections/collection_taglisting.feature
+++ b/features/collections/collection_taglisting.feature
@@ -4,7 +4,7 @@ Feature: Collection
As a humble user
I want to locate and browse through tag collection listings
- Scenario: Tags and synonyms of the tag show up in the tag's collection listing
+ Scenario: Collections tagged with a tag and synonyms of the tag show up in the tag's collection listing
Given a set of collections for tag page searching
When I go to the collections page
And I follow "My Beautiful Canonical Tag"
@@ -29,11 +29,11 @@ Feature: Collection
And I should see "Gorgeous Tag Test Collection"
But I should not see "Noncanonical Tag Test Collection"
- Scenario: We can further filter a tag's collection listing with collection_search_tag
+ Scenario: We can further filter a tag's collection listing with another tag
Given a set of collections for tag page searching
When I go to the collections page
And I follow "My Beautiful Canonical Tag"
- And I fill in "collection_search_tag" with "a noncanonical tag"
+ And I fill in "Filter by tag" with "a noncanonical tag"
And I press "Sort and Filter"
Then I should see "My Beautiful Canonical Tag" within "h2.heading"
And I should see "1 Collection" within "h2.heading"
@@ -46,7 +46,7 @@ Feature: Collection
Given a set of collections for tag page searching
When I go to the collections page
And I follow "My Beautiful Canonical Tag"
- And I choose "collection_search_challenge_type_giftexchange"
+ And I choose "Gift Exchange Challenge"
And I press "Sort and Filter"
Then I should see "My Beautiful Canonical Tag" within "h2.heading"
And I should see "1 Collection" within "h2.heading"
@@ -59,7 +59,7 @@ Feature: Collection
Given a set of collections for tag page searching
When I go to the collections page
And I follow "My Beautiful Canonical Tag"
- And I choose "collection_search_challenge_type_giftexchange"
+ And I choose "Gift Exchange Challenge"
And I press "Sort and Filter"
Then I should see "My Beautiful Canonical Tag" within "h2.heading"
And I should see "1 Collection" within "h2.heading"
@@ -103,11 +103,10 @@ Feature: Collection
And I fill in "Collection Tags" with ""
And I press "Update"
And all indexing jobs have been run
- And I view the tag "My Beautiful Canonical Tag"
- And I follow "Collections" within ".primary.header.module"
+ And I go to the collections tagged "My Beautiful Canonical Tag"
Then I should see "My Beautiful Canonical Tag" within "h2.heading"
And I should see "2 Collections" within "h2.heading"
And I should see "Multiple Tag Test Collection"
And I should see "Gorgeous Tag Test Collection"
But I should not see "Beautiful Tag Test Collection"
- And I should not see "Noncanonical Tag Test Collection"
\ No newline at end of file
+ And I should not see "Noncanonical Tag Test Collection"
From e220157d1870829c8678040496eb51ccd141c9d6 Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Mon, 12 Oct 2026 21:28:46 +0000
Subject: [PATCH 26/32] AO3-7144 Change work/#/collections page title to
include search_helper
---
app/views/collections/index.html.erb | 4 ++--
config/locales/views/en.yml | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/app/views/collections/index.html.erb b/app/views/collections/index.html.erb
index df5aa6cc711..a0dcd6dff5d 100755
--- a/app/views/collections/index.html.erb
+++ b/app/views/collections/index.html.erb
@@ -5,9 +5,9 @@
<% elsif @collection %>
<%= search_header(@collections, @query, t(".page_heading.subcollection"), @owner) %>
<% elsif @work %>
- <%= t(".page_heading.collections_including", work: @work.title) %>
+ <%= t(".page_heading.collections_including", work: @work.title, collections: search_header(@collections, @query, t(".page_heading.collection"), @owner)) %>
<% else %>
- <%= t(".page_heading.collections_in_the", collections: search_header(@collections, @query, t(".page_heading.collection"), @owner), archive: ArchiveConfig.APP_NAME) %>
+ <%= t(".page_heading.collections_in_the", archive: ArchiveConfig.APP_NAME, collections: search_header(@collections, @query, t(".page_heading.collection"), @owner)) %>
<% end %>
diff --git a/config/locales/views/en.yml b/config/locales/views/en.yml
index d31ea030e2f..c5a47e90253 100644
--- a/config/locales/views/en.yml
+++ b/config/locales/views/en.yml
@@ -897,7 +897,7 @@ en:
page_heading:
collection: Collection
collections_in_the: "%{collections} in the %{archive}"
- collections_including: Collections including %{work}
+ collections_including: "%{collections} including %{work}"
subcollection: Subcollection
sidebar:
bookmarks: Bookmarked Items (%{count})
From f29ce2dc89091cceeb6933f37c75c83d546f9340 Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Tue, 13 Oct 2026 18:45:27 +0000
Subject: [PATCH 27/32] AO3-7144-7147 Fix works/#/collections title; factor out
load_owner
---
app/controllers/application_controller.rb | 45 +++++++++++++++++++++++
app/controllers/bookmarks_controller.rb | 27 +-------------
app/controllers/collections_controller.rb | 14 +------
app/controllers/works_controller.rb | 26 +------------
4 files changed, 49 insertions(+), 63 deletions(-)
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 3fa550fb219..ae9791253b7 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -354,6 +354,51 @@ def load_collection
@collection = Collection.find_by(name: params[:collection_id]) if params[:collection_id]
end
+ # obj_name: "work", "bookmark", or "collection" (used in the respective controllers)
+ def general_load_owner(obj_name)
+ @work = Work.find(params[:work_id]) if params[:work_id].present?
+ @collection = Collection.find_by!(name: params[:collection_id]) if params[:collection_id].present?
+ @language = Language.find_by(short: params[:language_id]) if params[:language_id].present?
+
+ if params[:user_id].present?
+ @user = User.find_by!(login: params[:user_id])
+
+ if params[:pseud_id].present?
+ @pseud = @user.pseuds.find_by!(name: params[:pseud_id])
+ end
+ end
+
+ if params[:tag_id].present?
+ @tag = Tag.find_by_name!(params[:tag_id])
+
+ unless @tag.canonical?
+ if @tag.merger.present?
+ case obj_name
+ when "collection"
+ redirect_to tag_collections_path(@tag.merger) and return
+ when "bookmark"
+ redirect_to tag_bookmarks_path(@tag.merger) and return
+ when "work"
+ redirect_path = @collection.present? ? collection_tag_works_path(@collection, @tag.merger) : tag_works_path(@tag.merger)
+ redirect_to redirect_path and return
+ end
+ else
+ redirect_to tag_path(@tag) and return
+ end
+ end
+ end
+
+ @owner = @user || @collection || @tag
+ @owner ||= case obj_name
+ when "work"
+ @pseud || @language
+ when "bookmark"
+ @pseud || @bookmarkable
+ when "collection"
+ @work
+ end
+ end
+
def privileged_collection_admin?
policy(Collection).access?
end
diff --git a/app/controllers/bookmarks_controller.rb b/app/controllers/bookmarks_controller.rb
index c4f43b87f1c..46c4a0dcdfb 100644
--- a/app/controllers/bookmarks_controller.rb
+++ b/app/controllers/bookmarks_controller.rb
@@ -252,32 +252,7 @@ def destroy
protected
def load_owner
- if params[:user_id].present?
- @user = User.find_by(login: params[:user_id])
- unless @user
- raise ActiveRecord::RecordNotFound, "Couldn't find user named '#{params[:user_id]}'"
- end
- if params[:pseud_id].present?
- @pseud = @user.pseuds.find_by(name: params[:pseud_id])
- unless @pseud
- raise ActiveRecord::RecordNotFound, "Couldn't find pseud named '#{params[:pseud_id]}'"
- end
- end
- end
- if params[:tag_id]
- @tag = Tag.find_by_name(params[:tag_id])
- unless @tag
- raise ActiveRecord::RecordNotFound, "Couldn't find tag named '#{params[:tag_id]}'"
- end
- unless @tag.canonical?
- if @tag.merger.present?
- redirect_to tag_bookmarks_path(@tag.merger) and return
- else
- redirect_to tag_path(@tag) and return
- end
- end
- end
- @owner = @bookmarkable || @pseud || @user || @collection || @tag
+ general_load_owner("bookmark")
end
def index_page_title
diff --git a/app/controllers/collections_controller.rb b/app/controllers/collections_controller.rb
index 77a7f3e6a65..8be3bfd1ae7 100644
--- a/app/controllers/collections_controller.rb
+++ b/app/controllers/collections_controller.rb
@@ -55,6 +55,7 @@ def index
@collections = @work.approved_collections
.by_title
.for_blurb
+ .page(params[:page])
elsif @collection.present?
@sort_and_filter = false
@search = CollectionSearchForm.new({ parent_id: @collection.id, sort_column: "title.keyword" }.merge(base_options))
@@ -213,18 +214,7 @@ def destroy
protected
def load_owner
- @user = User.find_by!(login: params[:user_id]) if params[:user_id].present?
- @work = Work.find(params[:work_id]) if params[:work_id].present?
- @collection = Collection.find_by!(name: params[:collection_id]) if params[:collection_id].present?
- if params[:tag_id].present?
- @tag = Tag.find_by_name!(params[:tag_id])
-
- unless @tag.canonical?
- redirect_path = @tag.merger.present? ? tag_collections_path(@tag.merger) : tag_path(@tag)
- redirect_to redirect_path and return
- end
- end
- @owner = @user || @work || @collection || @tag
+ general_load_owner("collection")
end
def add_owner(options)
diff --git a/app/controllers/works_controller.rb b/app/controllers/works_controller.rb
index 2a2929a326d..318ca41a621 100755
--- a/app/controllers/works_controller.rb
+++ b/app/controllers/works_controller.rb
@@ -724,31 +724,7 @@ def mark_as_read
protected
def load_owner
- if params[:user_id].present?
- @user = User.find_by!(login: params[:user_id])
- if params[:pseud_id].present?
- @pseud = @user.pseuds.find_by(name: params[:pseud_id])
- end
- end
- if params[:tag_id]
- @tag = Tag.find_by_name(params[:tag_id])
- unless @tag && @tag.is_a?(Tag)
- raise ActiveRecord::RecordNotFound, "Couldn't find tag named '#{params[:tag_id]}'"
- end
- unless @tag.canonical?
- if @tag.merger.present?
- if @collection.present?
- redirect_to(collection_tag_works_path(@collection, @tag.merger)) && return
- else
- redirect_to(tag_works_path(@tag.merger)) && return
- end
- else
- redirect_to(tag_path(@tag)) && return
- end
- end
- end
- @language = Language.find_by(short: params[:language_id]) if params[:language_id].present?
- @owner = @pseud || @user || @collection || @tag || @language
+ general_load_owner("work")
end
def load_work
From 7be48bb7eb4a72ff077622065f0c7669617e31c9 Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Tue, 13 Oct 2026 20:20:46 +0000
Subject: [PATCH 28/32] AO3-7144-7147 Appease linter + fix owner precedence
---
app/controllers/application_controller.rb | 47 +++++++++----------
app/controllers/bookmarks_controller.rb | 6 +--
app/controllers/collections_controller.rb | 8 ++--
app/controllers/works_controller.rb | 6 +--
features/step_definitions/collection_steps.rb | 6 +--
5 files changed, 34 insertions(+), 39 deletions(-)
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index ae9791253b7..262dc880720 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -355,48 +355,43 @@ def load_collection
end
# obj_name: "work", "bookmark", or "collection" (used in the respective controllers)
- def general_load_owner(obj_name)
+ def load_owner(obj_name)
@work = Work.find(params[:work_id]) if params[:work_id].present?
@collection = Collection.find_by!(name: params[:collection_id]) if params[:collection_id].present?
@language = Language.find_by(short: params[:language_id]) if params[:language_id].present?
if params[:user_id].present?
@user = User.find_by!(login: params[:user_id])
-
- if params[:pseud_id].present?
- @pseud = @user.pseuds.find_by!(name: params[:pseud_id])
- end
+ @pseud = @user.pseuds.find_by!(name: params[:pseud_id]) if params[:pseud_id].present?
end
if params[:tag_id].present?
@tag = Tag.find_by_name!(params[:tag_id])
unless @tag.canonical?
- if @tag.merger.present?
- case obj_name
- when "collection"
- redirect_to tag_collections_path(@tag.merger) and return
- when "bookmark"
- redirect_to tag_bookmarks_path(@tag.merger) and return
- when "work"
- redirect_path = @collection.present? ? collection_tag_works_path(@collection, @tag.merger) : tag_works_path(@tag.merger)
- redirect_to redirect_path and return
- end
- else
- redirect_to tag_path(@tag) and return
+ redirect_to tag_path(@tag) and return unless @tag.merger.present?
+
+ case obj_name
+ when "collection"
+ redirect_to tag_collections_path(@tag.merger) and return
+ when "bookmark"
+ redirect_to tag_bookmarks_path(@tag.merger) and return
+ when "work"
+ redirect_path = @collection.present? ? collection_tag_works_path(@collection, @tag.merger) : tag_works_path(@tag.merger)
+ redirect_to redirect_path and return
end
end
end
- @owner = @user || @collection || @tag
- @owner ||= case obj_name
- when "work"
- @pseud || @language
- when "bookmark"
- @pseud || @bookmarkable
- when "collection"
- @work
- end
+ # can't factor out shared user/collection/tag variables because precedence matters
+ @owner = case obj_name
+ when "work"
+ @pseud || @user || @collection || @tag || @language
+ when "bookmark"
+ @bookmarkable || @pseud || @user || @collection || @tag
+ when "collection"
+ @user || @work || @collection || @tag
+ end
end
def privileged_collection_admin?
diff --git a/app/controllers/bookmarks_controller.rb b/app/controllers/bookmarks_controller.rb
index 46c4a0dcdfb..17b24ee630e 100644
--- a/app/controllers/bookmarks_controller.rb
+++ b/app/controllers/bookmarks_controller.rb
@@ -1,6 +1,6 @@
class BookmarksController < ApplicationController
before_action :load_collection
- before_action :load_owner, only: [:index]
+ before_action :load_bookmark_owner, only: [:index]
before_action :load_bookmarkable, only: [:index, :new, :create]
before_action :users_only, only: [:new, :create, :edit, :update]
before_action :check_user_status, only: [:new, :create, :edit, :update]
@@ -251,8 +251,8 @@ def destroy
protected
- def load_owner
- general_load_owner("bookmark")
+ def load_bookmark_owner
+ load_owner("bookmark")
end
def index_page_title
diff --git a/app/controllers/collections_controller.rb b/app/controllers/collections_controller.rb
index 8be3bfd1ae7..a5936b55a01 100644
--- a/app/controllers/collections_controller.rb
+++ b/app/controllers/collections_controller.rb
@@ -1,5 +1,5 @@
class CollectionsController < ApplicationController
- before_action :load_owner, only: [:index]
+ before_action :load_collection_owner, only: [:index]
before_action :users_only, only: [:new, :create]
before_action :load_collection_from_id, only: [:show, :edit, :update, :destroy, :confirm_delete]
before_action :collection_owners_or_privileged_admins_only, only: [:edit]
@@ -72,7 +72,7 @@ def index
@collections = @search.search_results.scope(:for_search)
end
- flash_search_warnings(@collections) if !@work.present?
+ flash_search_warnings(@collections) unless @work.present?
@pagy = pagy_query_result(@collections) if @collections.respond_to?(:total_pages)
end
@@ -213,8 +213,8 @@ def destroy
protected
- def load_owner
- general_load_owner("collection")
+ def load_collection_owner
+ load_owner("collection")
end
def add_owner(options)
diff --git a/app/controllers/works_controller.rb b/app/controllers/works_controller.rb
index 318ca41a621..c18ee810a5e 100755
--- a/app/controllers/works_controller.rb
+++ b/app/controllers/works_controller.rb
@@ -5,7 +5,7 @@ class WorksController < ApplicationController
# only registered users and NOT admin should be able to create new works
before_action :load_collection
- before_action :load_owner, only: [:index]
+ before_action :load_work_owner, only: [:index]
before_action :users_only, except: [:index, :show, :navigate, :search, :collected, :edit, :update, :drafts, :share]
before_action :check_user_status, except: [:index, :edit, :edit_multiple, :confirm_delete_multiple, :delete_multiple, :confirm_delete, :destroy, :show, :show_multiple, :navigate, :search, :collected, :share]
before_action :check_user_not_suspended, only: [:edit, :confirm_delete, :destroy, :show_multiple, :edit_multiple, :confirm_delete_multiple, :delete_multiple]
@@ -723,8 +723,8 @@ def mark_as_read
protected
- def load_owner
- general_load_owner("work")
+ def load_work_owner
+ load_owner("work")
end
def load_work
diff --git a/features/step_definitions/collection_steps.rb b/features/step_definitions/collection_steps.rb
index 90ee86726e2..9c77c11039f 100644
--- a/features/step_definitions/collection_steps.rb
+++ b/features/step_definitions/collection_steps.rb
@@ -180,10 +180,10 @@
end
Given "a set of collections for tag page searching" do
- beautiful = Fandom.where(name: "My Beautiful Canonical Tag", canonical: true).first_or_create
- gorgeous = Fandom.find_or_create_by(name: "My Gorgeous Synonymous Tag")
+ beautiful = Fandom.where(name: "My Beautiful Canonical Tag", canonical: true).first_or_create!
+ gorgeous = Fandom.find_or_create_by!(name: "My Gorgeous Synonymous Tag")
gorgeous.reload.merger = beautiful
- gorgeous.save
+ gorgeous.save!
profile = CollectionProfile.create!(faq: "FAQ goes here",
intro: "Intro goes here",
rules: "Rules go here")
From 99f3a6683729efc25f93a522c113d5fa17f4f047 Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Tue, 13 Oct 2026 20:30:45 +0000
Subject: [PATCH 29/32] AO3-7144-7147 Appease linter again
---
app/controllers/application_controller.rb | 6 +++---
app/controllers/collections_controller.rb | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 262dc880720..f855ae54854 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -369,16 +369,16 @@ def load_owner(obj_name)
@tag = Tag.find_by_name!(params[:tag_id])
unless @tag.canonical?
- redirect_to tag_path(@tag) and return unless @tag.merger.present?
+ redirect_to tag_path(@tag) and return if @tag.merger.blank?
+ work_redirect_path = @collection.present? ? collection_tag_works_path(@collection, @tag.merger) : tag_works_path(@tag.merger)
case obj_name
when "collection"
redirect_to tag_collections_path(@tag.merger) and return
when "bookmark"
redirect_to tag_bookmarks_path(@tag.merger) and return
when "work"
- redirect_path = @collection.present? ? collection_tag_works_path(@collection, @tag.merger) : tag_works_path(@tag.merger)
- redirect_to redirect_path and return
+ redirect_to work_redirect_path and return
end
end
end
diff --git a/app/controllers/collections_controller.rb b/app/controllers/collections_controller.rb
index a5936b55a01..9ed13baded8 100644
--- a/app/controllers/collections_controller.rb
+++ b/app/controllers/collections_controller.rb
@@ -72,7 +72,7 @@ def index
@collections = @search.search_results.scope(:for_search)
end
- flash_search_warnings(@collections) unless @work.present?
+ flash_search_warnings(@collections) if @work.blank?
@pagy = pagy_query_result(@collections) if @collections.respond_to?(:total_pages)
end
From 116fb1c429f05f583281ce85030ab5a5c9893b1c Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Tue, 13 Oct 2026 22:15:13 +0000
Subject: [PATCH 30/32] AO3-7147 Fix error messages for load_owner
---
app/controllers/application_controller.rb | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index f855ae54854..866afdb84a4 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -361,13 +361,23 @@ def load_owner(obj_name)
@language = Language.find_by(short: params[:language_id]) if params[:language_id].present?
if params[:user_id].present?
- @user = User.find_by!(login: params[:user_id])
- @pseud = @user.pseuds.find_by!(name: params[:pseud_id]) if params[:pseud_id].present?
+ @user = User.find_by(login: params[:user_id])
+ unless @user
+ raise ActiveRecord::RecordNotFound, "Couldn't find user named '#{params[:user_id]}'"
+ end
+ if params[:pseud_id].present?
+ @pseud = @user.pseuds.find_by(name: params[:pseud_id])
+ if @pseud.blank? and obj_name == "bookmark"
+ raise ActiveRecord::RecordNotFound, "Couldn't find pseud named '#{params[:pseud_id]}'"
+ end
+ end
end
if params[:tag_id].present?
- @tag = Tag.find_by_name!(params[:tag_id])
-
+ @tag = Tag.find_by_name(params[:tag_id])
+ unless @tag && @tag.is_a?(Tag)
+ raise ActiveRecord::RecordNotFound, "Couldn't find tag named '#{params[:tag_id]}'"
+ end
unless @tag.canonical?
redirect_to tag_path(@tag) and return if @tag.merger.blank?
From 834a4a3577bde24a1f879284dd0eaba81461279d Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Tue, 13 Oct 2026 22:25:35 +0000
Subject: [PATCH 31/32] AO3-7147 Appease linter again
---
app/controllers/application_controller.rb | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 866afdb84a4..b60cdcdb923 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -362,22 +362,18 @@ def load_owner(obj_name)
if params[:user_id].present?
@user = User.find_by(login: params[:user_id])
- unless @user
- raise ActiveRecord::RecordNotFound, "Couldn't find user named '#{params[:user_id]}'"
- end
+ raise ActiveRecord::RecordNotFound, "Couldn't find user named '#{params[:user_id]}'" if @user.blank?
+
if params[:pseud_id].present?
@pseud = @user.pseuds.find_by(name: params[:pseud_id])
- if @pseud.blank? and obj_name == "bookmark"
- raise ActiveRecord::RecordNotFound, "Couldn't find pseud named '#{params[:pseud_id]}'"
- end
+ raise ActiveRecord::RecordNotFound, "Couldn't find pseud named '#{params[:pseud_id]}'" if @pseud.blank? && obj_name == "bookmark"
end
end
if params[:tag_id].present?
@tag = Tag.find_by_name(params[:tag_id])
- unless @tag && @tag.is_a?(Tag)
- raise ActiveRecord::RecordNotFound, "Couldn't find tag named '#{params[:tag_id]}'"
- end
+ raise ActiveRecord::RecordNotFound, "Couldn't find tag named '#{params[:tag_id]}'" unless @tag&.is_a?(Tag)
+
unless @tag.canonical?
redirect_to tag_path(@tag) and return if @tag.merger.blank?
From e4a383d214da9f2d02717b74583de4f9251fc673 Mon Sep 17 00:00:00 2001
From: techlingyi <166869872+techlingyi@users.noreply.github.com>
Date: Tue, 13 Oct 2026 22:30:06 +0000
Subject: [PATCH 32/32] AO3-7147 Appease linter once more
---
app/controllers/application_controller.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index b60cdcdb923..c038d3722c5 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -372,7 +372,7 @@ def load_owner(obj_name)
if params[:tag_id].present?
@tag = Tag.find_by_name(params[:tag_id])
- raise ActiveRecord::RecordNotFound, "Couldn't find tag named '#{params[:tag_id]}'" unless @tag&.is_a?(Tag)
+ raise ActiveRecord::RecordNotFound, "Couldn't find tag named '#{params[:tag_id]}'" unless @tag.is_a?(Tag)
unless @tag.canonical?
redirect_to tag_path(@tag) and return if @tag.merger.blank?