Skip to content

Commit b69123b

Browse files
committed
Merge branch 'feature/ransack-scopes' into easypep-master
2 parents d6906ec + e81e3bf commit b69123b

3 files changed

Lines changed: 54 additions & 4 deletions

File tree

lib/jsonapi/filtering.rb

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,11 @@ def self.extract_attributes_and_predicates(requested_field, allowed_fields)
3535
# @param allowed_fields [Array] a list of allowed fields to be filtered
3636
# @param options [Hash] extra flags to enable/disable features
3737
# @return [ActiveRecord::Base] a collection of resources
38-
def jsonapi_filter(resources, allowed_fields, options = {})
38+
def jsonapi_filter(resources, allowed_fields, *allowed_scopes, options)
39+
options = options || {}
40+
allowed_scopes = (allowed_scopes || []).flatten.map(&:to_s)
3941
allowed_fields = allowed_fields.map(&:to_s)
40-
extracted_params = jsonapi_filter_params(allowed_fields)
42+
extracted_params = jsonapi_filter_params(allowed_fields, allowed_scopes)
4143
extracted_params[:sorts] = jsonapi_sort_params(allowed_fields, options)
4244
resources = resources.ransack(extracted_params)
4345
block_given? ? yield(resources) : resources
@@ -50,7 +52,7 @@ def jsonapi_filter(resources, allowed_fields, options = {})
5052
#
5153
# @param allowed_fields [Array] a list of allowed fields to be filtered
5254
# @return [Hash] to be passed to [ActiveRecord::Base#order]
53-
def jsonapi_filter_params(allowed_fields)
55+
def jsonapi_filter_params(allowed_fields, allowed_scopes)
5456
filtered = {}
5557
requested = params[:filter] || {}
5658
allowed_fields = allowed_fields.map(&:to_s)
@@ -65,6 +67,20 @@ def jsonapi_filter_params(allowed_fields)
6567
to_filter = to_filter.split(',')
6668
end
6769

70+
# filter by scopes expects an exact match
71+
# with the `allowed_scopes`. Predicates can be a part of named scopes
72+
# and should be handled first
73+
# Make sure to move to the next after a match
74+
# {"created_before"=>"2013-02-01"}
75+
# {"created_before_gt"=>"2013-02-01"}
76+
if allowed_scopes.include?(requested_field)
77+
filtered[requested_field] = to_filter
78+
next
79+
end
80+
81+
82+
# filter by attributes
83+
# {"first_name_eq"=>"Beau"}
6884
if predicates.any? && (field_names - allowed_fields).empty?
6985
filtered[requested_field] = to_filter
7086
end

spec/dummy.rb

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@
3232

3333
class User < ActiveRecord::Base
3434
has_many :notes
35+
scope :created_before, ->(date) { where('created_at < ?', date) }
36+
37+
def self.ransackable_scopes(auth_object = nil)
38+
%i(created_before)
39+
end
3540
end
3641

3742
class Note < ActiveRecord::Base
@@ -87,9 +92,15 @@ def index
8792
:notes_created_at, :notes_quantity,
8893
:notes_count
8994
]
95+
allowed_scopes = [
96+
:created_before
97+
]
9098
options = { sort_with_expressions: true }
9199

92-
jsonapi_filter(User.all, allowed_fields, options) do |filtered|
100+
jsonapi_filter(User.all,
101+
allowed_fields,
102+
allowed_scopes,
103+
options) do |filtered|
93104
result = filtered.result
94105

95106
if params[:sort].to_s.include?('notes_quantity')

spec/filtering_spec.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,29 @@
135135
expect(response_json['data'][0]).to have_id(second_user.id.to_s)
136136
end
137137
end
138+
139+
context 'returns users filtered by scope' do
140+
let(:params) do
141+
third_user.update(created_at: '2013-01-01')
142+
143+
{
144+
filter: { created_before: '2013-02-01' }
145+
}
146+
end
147+
148+
it 'ensures ransack scopes are working properly' do
149+
ransack = User.ransack({ created_before: '2013-02-01' })
150+
expected_sql = 'SELECT "users".* FROM "users" WHERE '\
151+
'(created_at < \'2013-02-01\')'
152+
expect(ransack.result.to_sql).to eq(expected_sql)
153+
end
154+
155+
it 'should return only' do
156+
expect(response).to have_http_status(:ok)
157+
expect(response_json['data'].size).to eq(1)
158+
expect(response_json['data'][0]).to have_id(third_user.id.to_s)
159+
end
160+
end
138161
end
139162
end
140163
end

0 commit comments

Comments
 (0)