From ab224d34b2426a26ef8a65281a0f156fbf688c8b Mon Sep 17 00:00:00 2001 From: Dwight Scott Date: Thu, 24 Feb 2022 12:34:50 -0500 Subject: [PATCH] Add ability to bulk search tags by name or id (#16671) * Trigger Build * Remove cache header before_action and add ability to search by tag name * Remove cache header before_action and add ability to search by tag name * Add internal bulk tag endpoint to get tags by array of names or ids * Restore V0 tags controller --- app/controllers/api/v0/tags_controller.rb | 10 +++---- app/controllers/tags_controller.rb | 20 +++++++++++++- app/views/api/v0/tags/index.json.jbuilder | 9 +------ config/routes.rb | 1 + spec/requests/api/v0/tags_spec.rb | 17 +----------- spec/requests/tags_spec.rb | 32 +++++++++++++++++++++++ 6 files changed, 58 insertions(+), 31 deletions(-) diff --git a/app/controllers/api/v0/tags_controller.rb b/app/controllers/api/v0/tags_controller.rb index 461d548ac..fe8e7a08a 100644 --- a/app/controllers/api/v0/tags_controller.rb +++ b/app/controllers/api/v0/tags_controller.rb @@ -3,19 +3,17 @@ module Api class TagsController < ApiController before_action :set_cache_control_headers, only: %i[index] - ATTRIBUTES_FOR_SERIALIZATION = %i[id name bg_color_hex text_color_hex short_summary badge_id].freeze + ATTRIBUTES_FOR_SERIALIZATION = %i[id name bg_color_hex text_color_hex].freeze private_constant :ATTRIBUTES_FOR_SERIALIZATION def index - @tags = Tag.includes(:badge).select(ATTRIBUTES_FOR_SERIALIZATION) - page = params[:page] per_page = (params[:per_page] || 10).to_i num = [per_page, 1000].min - @tags = @tags.where(id: params[:tag_ids]) if params[:tag_ids].present? - - @tags = @tags.order(taggings_count: :desc).page(page).per(num) + @tags = Tag.select(ATTRIBUTES_FOR_SERIALIZATION) + .order(taggings_count: :desc) + .page(page).per(num) set_surrogate_key_header Tag.table_key, @tags.map(&:record_key) end diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb index b08c0ed55..5217591f7 100644 --- a/app/controllers/tags_controller.rb +++ b/app/controllers/tags_controller.rb @@ -3,7 +3,7 @@ class TagsController < ApplicationController before_action :authenticate_user!, only: %i[edit update] after_action :verify_authorized - ATTRIBUTES_FOR_SERIALIZATION = %i[id name bg_color_hex text_color_hex].freeze + ATTRIBUTES_FOR_SERIALIZATION = %i[id name bg_color_hex text_color_hex short_summary badge_id].freeze INDEX_API_ATTRIBUTES = %i[name rules_html short_summary bg_color_hex badge_id].freeze TAGS_ALLOWED_PARAMS = %i[ @@ -21,6 +21,24 @@ class TagsController < ApplicationController @tags = params[:q].present? ? tags.search_by_name(params[:q]) : tags.order(hotness_score: :desc) end + def bulk + skip_authorization + @tags = Tag.includes(:badge).select(ATTRIBUTES_FOR_SERIALIZATION) + + page = params[:page] + per_page = (params[:per_page] || 10).to_i + num = [per_page, 1000].min + + if params[:tag_ids].present? + @tags = @tags.where(id: params[:tag_ids]) + elsif params[:tag_names].present? + @tags = @tags.where(name: params[:tag_names]) + end + + @tags = @tags.order(taggings_count: :desc).page(page).per(num) + render json: @tags, only: ATTRIBUTES_FOR_SERIALIZATION, include: [badge: { only: [:badge_image] }] + end + def edit @tag = Tag.find_by!(name: params[:tag]) authorize @tag diff --git a/app/views/api/v0/tags/index.json.jbuilder b/app/views/api/v0/tags/index.json.jbuilder index aa7017efd..f95de7d02 100644 --- a/app/views/api/v0/tags/index.json.jbuilder +++ b/app/views/api/v0/tags/index.json.jbuilder @@ -1,10 +1,3 @@ json.array! @tags.each do |tag| - json.extract!(tag, :id, :name, :bg_color_hex, :text_color_hex, :short_summary) - json.badge do - if tag.badge - json.badge_image tag.badge.badge_image - else - json.badge_image nil - end - end + json.extract!(tag, :id, :name, :bg_color_hex, :text_color_hex) end diff --git a/config/routes.rb b/config/routes.rb index bf01d6844..224f0fd95 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -151,6 +151,7 @@ Rails.application.routes.draw do collection do get "/onboarding", to: "tags#onboarding" get "/suggest", to: "tags#suggest", defaults: { format: :json } + get "/bulk", to: "tags#bulk", defaults: { format: :json } end end resources :stripe_active_cards, only: %i[create update destroy] diff --git a/spec/requests/api/v0/tags_spec.rb b/spec/requests/api/v0/tags_spec.rb index cee0dca01..53cca6680 100644 --- a/spec/requests/api/v0/tags_spec.rb +++ b/spec/requests/api/v0/tags_spec.rb @@ -21,9 +21,6 @@ RSpec.describe "Api::V0::Tags", type: :request do response_tag_with_badge = response.parsed_body.last expect_valid_json_body(response_tag, tag) expect_valid_json_body(response_tag_with_badge, tag_with_badge) - - expect(response_tag["badge"]["badge_image"]).to be_nil - expect(response_tag_with_badge["badge"]["badge_image"]["url"]).to eq(tag_with_badge.badge.badge_image.url) end it "orders tags by taggings_count in a descending order" do @@ -36,15 +33,6 @@ RSpec.describe "Api::V0::Tags", type: :request do expect(response.parsed_body.map { |t| t["id"] }).to eq(expected_result) end - it "finds tags from array of tag_ids" do - tags = create_list(:tag, 10, taggings_count: 10) - tag_ids = tags.sample(4).map(&:id) - - get api_tags_path, params: { tag_ids: tag_ids } - - expect(response.parsed_body.map { |t| t["id"] }).to match_array(tag_ids) - end - it "supports pagination" do create_list(:tag, 3) @@ -68,13 +56,10 @@ RSpec.describe "Api::V0::Tags", type: :request do private def expect_valid_json_body(body, tag) - expect(body.keys).to match_array(%w[id name bg_color_hex text_color_hex short_summary badge]) + expect(body.keys).to match_array(%w[id name bg_color_hex text_color_hex]) expect(body["id"]).to eq(tag.id) expect(body["name"]).to eq(tag.name) expect(body["bg_color_hex"]).to eq(tag.bg_color_hex) expect(body["text_color_hex"]).to eq(tag.text_color_hex) - expect(body["short_summary"]).to eq(tag.short_summary) - expect(body).to have_key("badge") - expect(body["badge"]).to have_key("badge_image") end end diff --git a/spec/requests/tags_spec.rb b/spec/requests/tags_spec.rb index 08137f9bc..2f62d3afc 100644 --- a/spec/requests/tags_spec.rb +++ b/spec/requests/tags_spec.rb @@ -34,6 +34,38 @@ RSpec.describe "Tags", type: :request, proper_status: true do end end + describe "GET /tags/bulk" do + it "returns a JSON representation of the top tags", :aggregate_failures do + tags = create_list(:tag, 10, taggings_count: 10) + tag_names = tags.sample(2).map(&:name) + tag_ids = tags.sample(4).map(&:id) + + get bulk_tags_path, params: { tag_names: tag_names, tag_ids: tag_ids } + + expect(response.parsed_body.map { |t| t["id"] }).to match_array(tag_ids) + expect(response).to have_http_status(:ok) + expect(response.content_type).to match(%r{application/json; charset=utf-8}i) + end + + it "finds tags from array of tag_ids" do + tags = create_list(:tag, 10, taggings_count: 10) + tag_ids = tags.sample(4).map(&:id) + + get bulk_tags_path, params: { tag_ids: tag_ids } + + expect(response.parsed_body.map { |t| t["id"] }).to match_array(tag_ids) + end + + it "finds tags from array of tag_names" do + tags = create_list(:tag, 10, taggings_count: 10) + tag_names = tags.sample(4).map(&:name) + + get bulk_tags_path, params: { tag_names: tag_names } + + expect(response.parsed_body.map { |t| t["name"] }).to match_array(tag_names) + end + end + describe "GET /tags/suggest" do it "returns a JSON representation of the top tags", :aggregate_failures do badge = create(:badge)