Skip to content

Add searchable image gallery with editable titles (#1512)#1543

Open
maebeale wants to merge 1 commit into
mainfrom
maebeale/daegu-v3
Open

Add searchable image gallery with editable titles (#1512)#1543
maebeale wants to merge 1 commit into
mainfrom
maebeale/daegu-v3

Conversation

@maebeale

@maebeale maebeale commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

Closes #1512

What is the goal of this PR and why is this important?

  • The team wants to use the portal's gallery images as an image database, but there was no way to browse or find them.
  • There was no gallery page, no search, and image titles could not be edited — so images couldn't be tagged with their organization, workshop, etc.
  • This adds an admin-only Image gallery so images can be tagged with meaningful titles and found again later.

How did you approach the change?

  • New GalleryAssetsController (index, update), reachable from the Curriculum → Image gallery nav item (admin-only).
  • index lists every gallery asset whose attached file is an image, newest first, paginated (24/page).
  • Search box debounces into a Turbo frame (reusing the existing collection Stimulus controller) and matches on the editable title, the owner type (Workshop, Story, …), and the original filename, via new GalleryAsset.images / GalleryAsset.search_metadata scopes.
  • Editable titles: each image card has an inline title field that PATCHes to update; the response re-renders just that card's Turbo frame, so tagging an image never reloads the page.
  • Authorization: GalleryAssetPolicy restricts both actions to admins (super users), consistent with the default policy; non-admins are redirected like elsewhere in the app.

Anything else to add?

  • Titles are intentionally free-text so the team can tag with whatever metadata is useful (org, workshop, program). Search matches that text plus owner type and filename.
  • Specs added: model (scopes), request (auth + search + inline edit), policy, and routing. All green locally (18 examples, 0 failures).
  • Screenshots to follow.

🤖 Generated with Claude Code

The team wants to use gallery images as an image database, but images were
impossible to find: there was no gallery page, no search, and titles could
not be edited to tag images with their organization, workshop, etc.

This adds an admin-only Image gallery that lists every attached gallery image,
lets you search by title/owner type/filename, and edit each image's title
inline so it can be tagged and found again.

Closes #1512

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 5, 2026 00:33

# Free-text search across the editable title, the owning record type, and the
# original filename — the metadata the team tags images with (org, workshop, etc.).
scope :search_metadata, ->(query) {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

search_metadata references active_storage_blobs, so it must be chained after .images (which joins the blob). The controller always does GalleryAsset.images.search_metadata(...). Matching on owner_type lets a search for "workshop" surface every workshop image even before it's been given a title.


def update
authorize! @gallery_asset
@gallery_asset.update(gallery_asset_params)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The form lives inside a per-card <turbo-frame>, so rendering just the _card partial here swaps that one card in place — editing a title never reloads the grid or loses the user's scroll/search position.

def index? = admin?
def update? = admin?

relation_scope do |relation|

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Admin-only: this is an internal image database. relation_scope returns none for non-admins so authorized_scope is safe even if the policy is later relaxed to expose index?.

@maebeale maebeale marked this pull request as ready for review June 5, 2026 00:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR adds an admin-only Image gallery feature for browsing, searching, and retitling existing GalleryAsset images so the portal’s gallery can be used as a searchable image database (matching on title, owner type, and original filename).

Changes:

  • Added GalleryAssetsController (index, update) plus routes and an admin-only navbar entry under Curriculum.
  • Implemented GalleryAsset.images and GalleryAsset.search_metadata scopes to filter to images and support free-text search over key metadata.
  • Added gallery UI (Turbo-frame-loaded results, searchable form, inline title editing) and accompanying policy + request/model/routing specs.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
spec/routing/gallery_assets_routing_spec.rb Adds routing coverage for the new gallery assets endpoints.
spec/requests/gallery_assets_spec.rb Adds request coverage for authorization, search, and inline title updates.
spec/policies/gallery_asset_policy_spec.rb Verifies admin-only access for index/update.
spec/models/gallery_asset_spec.rb Covers the new .images and .search_metadata scopes.
config/routes.rb Exposes gallery_assets#index and gallery_assets#update.
app/views/shared/_navbar_menu.html.erb Adds the admin-only “Image gallery” link in the Curriculum dropdown.
app/views/gallery_assets/results.html.erb Turbo-frame results view: count, grid, pagination, empty state.
app/views/gallery_assets/index.html.erb Gallery page shell + Turbo-frame skeleton loader.
app/views/gallery_assets/_search.html.erb Search form wired to Turbo frame via the existing collection controller.
app/views/gallery_assets/_card.html.erb Image card UI with inline title edit form and owner type display.
app/policies/gallery_asset_policy.rb Introduces admin-only authorization and relation scoping for gallery assets.
app/models/gallery_asset.rb Adds scopes for image filtering and metadata search.
app/controllers/gallery_assets_controller.rb Implements listing/searching/pagination and inline title update rendering.
AGENTS.md Updates directory file counts after adding controller/policy.

Comment on lines +4 to +15
def index
authorize! GalleryAsset
@query = params[:query].to_s.strip

scope = authorized_scope(GalleryAsset.images.with_attached_file.includes(:owner))
scope = scope.search_metadata(@query) if @query.present?
scope = scope.order(created_at: :desc)

@count = scope.count
@gallery_assets = scope.paginate(page: params[:page], per_page: 24)

render :results if turbo_frame_request?
Comment on lines +11 to +18
scope :search_metadata, ->(query) {
next all if query.blank?

term = "%#{sanitize_sql_like(query)}%"
where(
"assets.title LIKE :term OR assets.owner_type LIKE :term OR active_storage_blobs.filename LIKE :term",
term: term
)
Comment on lines +16 to +18
<button type="submit" class="absolute right-2 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-700">
<i class="fa fa-search"></i>
</button>
Comment on lines +44 to +49
<% if allowed_to?(:index?, GalleryAsset) %>
<%= link_to gallery_assets_path,
class: "admin-only bg-blue-100 flex items-center gap-2 px-4 py-2 text-sm text-gray-700 hover:bg-gray-100" do %>
<i class="fas fa-images"></i>
<span>Image gallery</span>
<% end %>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Gallery: search and editable titles to use gallery as image database

2 participants