[deploy] Update URLSearchParams to handle arrays correctly for Rails (#7300)

This commit is contained in:
Molly Struve 2020-04-15 14:58:18 -05:00 committed by GitHub
parent 2c6a4b4ecf
commit 223703f0d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 62 additions and 33 deletions

View file

@ -3,12 +3,14 @@ class SearchController < ApplicationController
before_action :format_integer_params
before_action :sanitize_params, only: %i[classified_listings]
CLASSIFIED_LISTINGS_PARAMS = %i[
category
classified_listing_search
page
per_page
tags
CLASSIFIED_LISTINGS_PARAMS = [
:category,
:classified_listing_search,
:page,
:per_page,
{
tags: []
},
].freeze
USER_PARAMS = %i[
@ -17,15 +19,17 @@ class SearchController < ApplicationController
per_page
].freeze
FEED_PARAMS = %i[
page
per_page
published_at
search_fields
sort_by
tag_names
user_id
class_name
FEED_PARAMS = [
:class_name,
:page,
:per_page,
:search_fields,
:sort_by,
:user_id,
{
tag_names: [],
published_at: [:gte]
},
].freeze
def tags

View file

@ -5,6 +5,7 @@ import {
hasInstantClick,
displaySearchResults,
fetchSearch,
createSearchUrl,
} from '../search';
import '../../../../assets/javascripts/lib/xss';
@ -61,7 +62,7 @@ describe('Search utilities', () => {
describe('preloadSearchResults', () => {
beforeEach(() => {
global.InstantClick = {
preload: url => url,
preload: (url) => url,
};
jest.spyOn(InstantClick, 'preload');
});
@ -145,7 +146,7 @@ describe('Search utilities', () => {
describe('displaySearchResults', () => {
beforeEach(() => {
global.InstantClick = {
display: url => url,
display: (url) => url,
};
jest.spyOn(InstantClick, 'display');
});
@ -242,10 +243,18 @@ describe('Search utilities', () => {
});
test('should return response formatted as JSON', () => {
responsePromise.then(response => {
responsePromise.then((response) => {
expect(response).toBeInstanceOf(Object);
expect(response).toMatchObject({ results: expect.any(Array) });
});
});
});
describe('createSearchUrl', () => {
test('should return a url string', () => {
const dataHash = { name: 'jav', tags: ['one', 'two'] };
const responseString = createSearchUrl(dataHash);
expect(responseString).toEqual('name=jav&tags%5B%5D=one&tags%5B%5D=two');
});
});
});

View file

@ -33,7 +33,7 @@ function fixedEncodeURIComponent(str) {
// from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
return encodeURIComponent(str).replace(
/[!'()*]/g,
c => `%${c.charCodeAt(0).toString(16)}`,
(c) => `%${c.charCodeAt(0).toString(16)}`,
);
}
@ -79,6 +79,22 @@ export function preloadSearchResults({
);
}
export function createSearchUrl(dataHash) {
const searchParams = new URLSearchParams();
Object.keys(dataHash).forEach((key) => {
const value = dataHash[key];
if (Array.isArray(value)) {
value.forEach((arrayValue) => {
searchParams.append(`${key}[]`, arrayValue);
});
} else {
searchParams.append(key, value);
}
});
return searchParams.toString();
}
/**
* A helper method to call /search endpoints.
*
@ -88,9 +104,9 @@ export function preloadSearchResults({
* @returns {Promise} A promise object with response formatted as JSON.
*/
export function fetchSearch(endpoint, dataHash) {
const searchParams = new URLSearchParams(dataHash).toString();
const searchUrl = createSearchUrl(dataHash);
return fetch(`/search/${endpoint}?${searchParams}`, {
return fetch(`/search/${endpoint}?${searchUrl}`, {
method: 'GET',
headers: {
Accept: 'application/json',
@ -98,5 +114,5 @@ export function fetchSearch(endpoint, dataHash) {
'Content-Type': 'application/json',
},
credentials: 'same-origin',
}).then(response => response.json());
}).then((response) => response.json());
}

View file

@ -63,7 +63,7 @@ module Search
TERM_KEYS.map do |term_key|
next unless @params.key? term_key
{ term: { term_key => @params[term_key] } }
{ terms: { term_key => Array.wrap(@params[term_key]) } }
end.compact
end

View file

@ -19,10 +19,10 @@ RSpec.describe Search::QueryBuilders::ClassifiedListing, type: :service do
params = { category: "cfp", tags: ["beginner"], contact_via_connect: false }
filter = described_class.new(params: params)
exepcted_filters = [
{ "term" => { "category" => "cfp" } },
{ "term" => { "tags" => ["beginner"] } },
{ "term" => { "contact_via_connect" => false } },
{ "term" => { "published" => true } },
{ "terms" => { "category" => ["cfp"] } },
{ "terms" => { "tags" => ["beginner"] } },
{ "terms" => { "contact_via_connect" => [false] } },
{ "terms" => { "published" => [true] } },
]
expect(filter.as_hash.dig("query", "bool", "filter")).to match_array(exepcted_filters)
end
@ -34,7 +34,7 @@ RSpec.describe Search::QueryBuilders::ClassifiedListing, type: :service do
exepcted_filters = [
{ "range" => { "bumped_at" => Time.current } },
{ "range" => { "expires_at" => 1.day.from_now } },
{ "term" => { "published" => true } },
{ "terms" => { "published" => [true] } },
]
expect(filter.as_hash.dig("query", "bool", "filter")).to match_array(exepcted_filters)
end
@ -60,8 +60,8 @@ RSpec.describe Search::QueryBuilders::ClassifiedListing, type: :service do
}]
exepcted_filters = [
{ "range" => { "bumped_at" => Time.current } },
{ "term" => { "category" => "cfp" } },
{ "term" => { "published" => true } },
{ "terms" => { "category" => ["cfp"] } },
{ "terms" => { "published" => [true] } },
]
expect(filter.as_hash.dig("query", "bool", "must")).to match_array(exepcted_query)
expect(filter.as_hash.dig("query", "bool", "filter")).to match_array(exepcted_filters)
@ -72,8 +72,8 @@ RSpec.describe Search::QueryBuilders::ClassifiedListing, type: :service do
params = { not_supported: "trash", category: "cfp" }
filter = described_class.new(params: params)
exepcted_filters = [
{ "term" => { "category" => "cfp" } },
{ "term" => { "published" => true } },
{ "terms" => { "category" => ["cfp"] } },
{ "terms" => { "published" => [true] } },
]
expect(filter.as_hash.dig("query", "bool", "filter")).to match_array(exepcted_filters)
end
@ -82,7 +82,7 @@ RSpec.describe Search::QueryBuilders::ClassifiedListing, type: :service do
filter = described_class.new(params: {}).as_hash
expect(filter.dig("sort")).to eq("bumped_at" => "desc")
expect(filter.dig("size")).to eq(0)
expect(filter.dig("query", "bool", "filter")).to match_array([{ "term" => { "published" => true } }])
expect(filter.dig("query", "bool", "filter")).to match_array([{ "terms" => { "published" => [true] } }])
end
it "allows default params to be overriden" do