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
This commit is contained in:
Dwight Scott 2022-02-24 12:34:50 -05:00 committed by GitHub
parent e0e4003671
commit ab224d34b2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 58 additions and 31 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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]

View file

@ -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

View file

@ -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)