@@ -70,6 +70,16 @@ def find_by_keys(keys, options = {})
70
70
resources_for ( records , options [ :context ] )
71
71
end
72
72
73
+ # Returns an array of Resources identified by the `keys` array. The resources are not filtered as this
74
+ # will have been done in a prior step
75
+ #
76
+ # @param keys [Array<key>] Array of primary keys to find resources for
77
+ # @option options [Hash] :context The context of the request, set in the controller
78
+ def find_to_populate_by_keys ( keys , options = { } )
79
+ records = records_for_populate ( options ) . where ( _primary_key => keys )
80
+ resources_for ( records , options [ :context ] )
81
+ end
82
+
73
83
# Finds Resource fragments using the `filters`. Pagination and sort options are used when provided.
74
84
# Retrieving the ResourceIdentities and attributes does not instantiate a model instance.
75
85
# Note: This is incompatible with Polymorphic resources (which are going to come from two separate tables)
@@ -242,10 +252,57 @@ def count_related(source_rid, relationship_name, options = {})
242
252
count_records ( records )
243
253
end
244
254
245
- def records ( _options = { } )
255
+ # This resource finder (ActiveRecordResourceFinder) uses an `ActiveRecord::Relation` as the starting point for
256
+ # retrieving models. From this relation filters, sorts and joins are applied as needed.
257
+ # Depending on which phase of the request processing different `records` methods will be called, giving the user
258
+ # the opportunity to override them differently for performance and security reasons.
259
+
260
+ # begin `records`methods
261
+
262
+ # Base for the `records` methods that follow and is not directly used for accessing model data by this class.
263
+ # Overriding this method gives a single place to affect the `ActiveRecord::Relation` used for the resource.
264
+ #
265
+ # @option options [Hash] :context The context of the request, set in the controller
266
+ #
267
+ # @return [ActiveRecord::Relation]
268
+ def records_base ( _options = { } )
246
269
_model_class . all
247
270
end
248
271
272
+ # The `ActiveRecord::Relation` used for finding user requested models. This may be overridden to enforce
273
+ # permissions checks on the request.
274
+ #
275
+ # @option options [Hash] :context The context of the request, set in the controller
276
+ #
277
+ # @return [ActiveRecord::Relation]
278
+ def records ( options = { } )
279
+ records_base ( options )
280
+ end
281
+
282
+ # The `ActiveRecord::Relation` used for populating the ResourceSet. Only resources that have been previously
283
+ # identified through the `records` method will be accessed. Thus it should not be necessary to reapply permissions
284
+ # checks. However if the model needs to include other models adding `includes` is appropriate
285
+ #
286
+ # @option options [Hash] :context The context of the request, set in the controller
287
+ #
288
+ # @return [ActiveRecord::Relation]
289
+ def records_for_populate ( options = { } )
290
+ records_base ( options )
291
+ end
292
+
293
+ # The `ActiveRecord::Relation` used for the finding related resources. Only resources that have been previously
294
+ # identified through the `records` method will be accessed and used as the basis to find related resources. Thus
295
+ # it should not be necessary to reapply permissions checks.
296
+ #
297
+ # @option options [Hash] :context The context of the request, set in the controller
298
+ #
299
+ # @return [ActiveRecord::Relation]
300
+ def records_for_source_to_related ( options = { } )
301
+ records_base ( options )
302
+ end
303
+
304
+ # end `records` methods
305
+
249
306
def apply_join ( records :, relationship :, resource_type :, join_type :, options :)
250
307
if relationship . polymorphic? && relationship . belongs_to?
251
308
case join_type
@@ -267,7 +324,7 @@ def apply_join(records:, relationship:, resource_type:, join_type:, options:)
267
324
end
268
325
269
326
def relationship_records ( relationship :, join_type : :inner , resource_type : nil , options : { } )
270
- records = relationship . parent_resource . records ( options )
327
+ records = relationship . parent_resource . records_for_source_to_related ( options )
271
328
strategy = relationship . options [ :apply_join ]
272
329
273
330
if strategy
@@ -336,7 +393,7 @@ def find_related_monomorphic_fragments(source_rids, relationship, options, conne
336
393
337
394
paginator = options [ :paginator ] if source_rids . count == 1
338
395
339
- records = apply_request_settings_to_records ( records : records ( options ) ,
396
+ records = apply_request_settings_to_records ( records : records_for_source_to_related ( options ) ,
340
397
resource_klass : resource_klass ,
341
398
sort_criteria : sort_criteria ,
342
399
primary_keys : source_ids ,
@@ -463,7 +520,7 @@ def find_related_polymorphic_fragments(source_rids, relationship, options, conne
463
520
464
521
# Note: We will sort by the source table. Without using unions we can't sort on a polymorphic relationship
465
522
# in any manner that makes sense
466
- records = apply_request_settings_to_records ( records : records ( options ) ,
523
+ records = apply_request_settings_to_records ( records : records_for_source_to_related ( options ) ,
467
524
resource_klass : resource_klass ,
468
525
sort_primary : true ,
469
526
primary_keys : source_ids ,
0 commit comments