Skip to content

Commit 1ea26b3

Browse files
committed
Give resource more control over sortable fields
I'm in a situation where I want clients to have repeatable, random sort order on a collection. My solution is to pass a ?sort=rand-N, with N being the seed used for sorting. This way, if the client was to page through the list or link to the list, the sort order would be preserved. For example, `/providers?sort=rand-42` would apply a random sort order with 42 as the key. To accommodate this, I need JSONAPI::RequestParser to allow sort keys that are not in a predetermined list. I think a good solution to this would be to have the RequestParser defer to the Resource when checking if a sort key is valid. The existing behaviour is maintained by moving the check on sortable_fields to sortable_field?, which can be overloaded by application specific resource classes.
1 parent 7ebba9b commit 1ea26b3

File tree

4 files changed

+26
-2
lines changed

4 files changed

+26
-2
lines changed

lib/jsonapi/request_parser.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -426,9 +426,8 @@ def parse_sort_criteria(resource_klass, sort_criteria)
426426

427427
def check_sort_criteria(resource_klass, sort_criteria)
428428
sort_field = sort_criteria[:field]
429-
sortable_fields = resource_klass.sortable_fields(context)
430429

431-
unless sortable_fields.include? sort_field.to_sym
430+
unless resource_klass.sortable_field?(sort_field.to_sym, context)
432431
@errors.concat(JSONAPI::Exceptions::InvalidSortCriteria
433432
.new(format_key(resource_klass._type), sort_field).errors)
434433
end

lib/jsonapi/resource.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,10 @@ def sortable_fields(_context = nil)
607607
_attributes.keys
608608
end
609609

610+
def sortable_field?(key, context = nil)
611+
sortable_fields(context).include? key.to_sym
612+
end
613+
610614
def fields
611615
_relationships.keys | _attributes.keys
612616
end

test/unit/jsonapi_request/jsonapi_request_test.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ def self.sortable_fields(context)
1414
end
1515
end
1616

17+
class TreeResource < JSONAPI::Resource
18+
def self.sortable_field?(key, context)
19+
key =~ /^sort\d+/
20+
end
21+
end
22+
1723
class JSONAPIRequestTest < ActiveSupport::TestCase
1824
def test_parse_includes_underscored
1925
params = ActionController::Parameters.new(
@@ -211,6 +217,15 @@ def test_parse_sort_with_valid_sorts
211217
assert_equal(sort_criteria, [{:field=>"name", :direction=>:desc}])
212218
end
213219

220+
def test_parse_sort_with_resource_validated_sorts
221+
setup_request
222+
sort_criteria = @request.parse_sort_criteria(TreeResource, "sort66,name")
223+
assert_equal(@request.errors.count, 1)
224+
assert_equal(@request.errors.first.title, "Invalid sort criteria")
225+
assert_equal(@request.errors.first.detail, "name is not a valid sort criteria for trees")
226+
assert_equal(sort_criteria, [{:field=>"sort66", :direction=>:asc}, {:field=>"name", :direction=>:asc}])
227+
end
228+
214229
def test_parse_sort_with_relationships
215230
setup_request
216231
sort_criteria = @request.parse_sort_criteria(CatResource, "-mother.name")

test/unit/resource/resource_test.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,4 +689,10 @@ def test_readonly_attribute
689689
refute_includes(PostWithReadonlyAttributesResource.creatable_fields, :author)
690690
refute_includes(PostWithReadonlyAttributesResource.updatable_fields, :author)
691691
end
692+
693+
def test_sortable_field?
694+
assert(PostResource.sortable_field?(:title))
695+
assert(PostResource.sortable_field?(:body))
696+
refute(PostResource.sortable_field?(:color))
697+
end
692698
end

0 commit comments

Comments
 (0)