From 70653b681d10917b77dced08f577446ced7568f1 Mon Sep 17 00:00:00 2001 From: erdgeist Date: Mon, 13 Jul 2026 03:22:37 +0200 Subject: Add RelatedAssetsController: search, attach, detach, reorder Backend for the asset-picker rebuild -- replaces the plan to dump every image asset in the system into a hidden, unfiltered browse panel on every node edit (the actual current behavior, confirmed by reading nodes/edit.html.erb directly) with a small, name-scoped search endpoint plus create/destroy/update for attach, detach, and reorder. No schema change needed -- RelatedAsset already had everything this requires (asset_id, page_id, an acts_as_list position). search excludes assets already attached to the page, keeping results meaningfully small given hundreds of assets total but only a handful per node in practice. create is find_or_create_by! rather than a bare create!, guarding against the same asset being attached twice from two separate search results. update leans on acts_as_list's own insert_at rather than custom position-shifting logic. Node#editable_page (autosave || draft || head) is extracted since this is now its third call site with identical logic -- deliberately not touching nodes#show, which resolves draft || head without autosave on purpose, a different and correct semantic for "current committed state" versus "what's actively being edited." --- test/controllers/related_assets_controller_test.rb | 83 ++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 test/controllers/related_assets_controller_test.rb (limited to 'test') diff --git a/test/controllers/related_assets_controller_test.rb b/test/controllers/related_assets_controller_test.rb new file mode 100644 index 0000000..a3082c2 --- /dev/null +++ b/test/controllers/related_assets_controller_test.rb @@ -0,0 +1,83 @@ +require 'test_helper' + +class RelatedAssetsControllerTest < ActionController::TestCase + test "search finds assets by name, excluding ones already attached" do + login_as :quentin + node = Node.root.children.create!(:slug => "related_assets_search_test") + + attached = Asset.create!(:name => "biometrics-scan", :upload_content_type => "image/png") + node.draft.assets << attached + + Asset.create!(:name => "biometrics-poster", :upload_content_type => "image/png") + Asset.create!(:name => "chaostreff-flyer", :upload_content_type => "image/png") + + get :search, params: { :node_id => node.id, :q => "biometrics" } + + json = JSON.parse(response.body) + names = json.map { |a| a["name"] } + assert_includes names, "biometrics-poster" + assert_not_includes names, "biometrics-scan" + assert_not_includes names, "chaostreff-flyer" + end + + test "search returns an empty list for a blank term" do + login_as :quentin + node = Node.root.children.create!(:slug => "related_assets_blank_search_test") + + get :search, params: { :node_id => node.id, :q => "" } + + assert_equal [], JSON.parse(response.body) + end + + test "create attaches an asset to the node's editable page" do + login_as :quentin + node = Node.root.children.create!(:slug => "related_assets_create_test") + asset = Asset.create!(:name => "erfa-photo", :upload_content_type => "image/png") + + post :create, params: { :node_id => node.id, :asset_id => asset.id } + + assert_response :success + assert_includes node.draft.reload.related_assets.map(&:asset_id), asset.id + end + + test "create does not duplicate an already-attached asset" do + login_as :quentin + node = Node.root.children.create!(:slug => "related_assets_dup_test") + asset = Asset.create!(:name => "erfa-photo-2", :upload_content_type => "image/png") + node.draft.assets << asset + + post :create, params: { :node_id => node.id, :asset_id => asset.id } + + assert_response :success + assert_equal 1, node.draft.reload.related_assets.count + end + + test "destroy removes the attached asset" do + login_as :quentin + node = Node.root.children.create!(:slug => "related_assets_destroy_test") + asset = Asset.create!(:name => "old-photo", :upload_content_type => "image/png") + node.draft.assets << asset + related = node.draft.related_assets.first + + delete :destroy, params: { :node_id => node.id, :id => related.id } + + assert_response :success + assert_equal 0, node.draft.reload.related_assets.count + end + + test "update reorders the attached assets" do + login_as :quentin + node = Node.root.children.create!(:slug => "related_assets_reorder_test") + first = Asset.create!(:name => "first-photo", :upload_content_type => "image/png") + second = Asset.create!(:name => "second-photo", :upload_content_type => "image/png") + node.draft.assets << first + node.draft.assets << second + + second_related = node.draft.related_assets.find_by(:asset_id => second.id) + patch :update, params: { :node_id => node.id, :id => second_related.id, :position => 1 } + + assert_response :success + ordered_asset_ids = node.draft.reload.related_assets.map(&:asset_id) + assert_equal [second.id, first.id], ordered_asset_ids + end +end -- cgit v1.3