Class: JsonapiCompliable::Sideload
- Inherits:
-
Object
- Object
- JsonapiCompliable::Sideload
- Defined in:
- lib/jsonapi_compliable/sideload.rb
Constant Summary
- HOOK_ACTIONS =
[:save, :create, :update, :destroy, :disassociate]
Instance Attribute Summary collapse
-
#assign_proc ⇒ Proc
readonly
The configured 'assign' block.
-
#foreign_key ⇒ Symbol
readonly
The attribute used to match objects - need not be a true database foreign key.
-
#grouping_field ⇒ Symbol
readonly
The configured 'group_by' symbol.
-
#name ⇒ Symbol
readonly
The name of the sideload.
-
#parent ⇒ Object
readonly
Returns the value of attribute parent.
-
#polymorphic ⇒ Boolean
readonly
Is this a polymorphic sideload?.
-
#polymorphic_groups ⇒ Hash
readonly
The subgroups, when polymorphic.
-
#primary_key ⇒ Symbol
readonly
The attribute used to match objects - need not be a true database primary key.
-
#resource_class ⇒ Class
readonly
The corresponding Resource class.
-
#scope_proc ⇒ Proc
readonly
The configured 'scope' block.
-
#sideloads ⇒ Hash
readonly
The associated sibling sideloads.
-
#type ⇒ Symbol
readonly
One of :has_many, :belongs_to, etc.
Instance Method Summary collapse
-
#after_save(only: [], except: [], &blk) ⇒ Object
Configure post-processing hooks.
- #all_sideloads ⇒ Object private
-
#allow_sideload(name, opts = {}, &blk) ⇒ Object
Configure a relationship between Resource objects.
-
#assign {|parents, children| ... } ⇒ Object
The proc used to assign the resolved parents and children.
-
#associate(parent, child) ⇒ Object
private
Configure how to associate parent and child records.
- #association_names(memo = []) ⇒ Object
-
#disassociate(parent, child) ⇒ Object
private
Configure how to disassociate parent and child records.
- #fire_hooks!(parent, objects, method) ⇒ Object
-
#group_by(grouping_field) ⇒ Object
Define an attribute that groups the parent records.
-
#hooks ⇒ Object
Get the hooks the user has configured.
-
#initialize(name, type: nil, resource: nil, polymorphic: false, primary_key: :id, foreign_key: nil, parent: nil) ⇒ Sideload
constructor
NB - the adapter's
#sideloading_module
is mixed in on instantiation. -
#polymorphic? ⇒ Boolean
Is this sideload polymorphic?.
- #polymorphic_child_for_type(type) ⇒ Object private
-
#resolve(parents, query, namespace) ⇒ void
private
Resolve the sideload.
-
#resource ⇒ Resource
An instance of
#resource_class
. -
#scope {|parents| ... } ⇒ Object
Build a scope that will be used to fetch the related records This scope will be further chained with filtering/sorting/etc.
-
#sideload(name) ⇒ Object
Fetch a Sideload object by its name.
Constructor Details
#initialize(name, type: nil, resource: nil, polymorphic: false, primary_key: :id, foreign_key: nil, parent: nil) ⇒ Sideload
NB - the adapter's #sideloading_module
is mixed in on
instantiation
An anonymous Resource will be assigned when none provided.
32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/jsonapi_compliable/sideload.rb', line 32 def initialize(name, type: nil, resource: nil, polymorphic: false, primary_key: :id, foreign_key: nil, parent: nil) @name = name @resource_class = (resource || Class.new(Resource)) @sideloads = {} @polymorphic = !!polymorphic @polymorphic_groups = {} if polymorphic? @parent = parent @primary_key = primary_key @foreign_key = foreign_key @type = type extend @resource_class.config[:adapter].sideloading_module end |
Instance Attribute Details
#assign_proc ⇒ Proc (readonly)
The configured 'assign' block
13 14 15 |
# File 'lib/jsonapi_compliable/sideload.rb', line 13 def assign_proc @assign_proc end |
#foreign_key ⇒ Symbol (readonly)
The attribute used to match objects - need not be a true database foreign key.
13 14 15 |
# File 'lib/jsonapi_compliable/sideload.rb', line 13 def foreign_key @foreign_key end |
#grouping_field ⇒ Symbol (readonly)
The configured 'group_by' symbol
13 14 15 |
# File 'lib/jsonapi_compliable/sideload.rb', line 13 def grouping_field @grouping_field end |
#name ⇒ Symbol (readonly)
The name of the sideload
13 14 15 |
# File 'lib/jsonapi_compliable/sideload.rb', line 13 def name @name end |
#parent ⇒ Object (readonly)
Returns the value of attribute parent
14 15 16 |
# File 'lib/jsonapi_compliable/sideload.rb', line 14 def parent @parent end |
#polymorphic ⇒ Boolean (readonly)
Is this a polymorphic sideload?
13 14 15 |
# File 'lib/jsonapi_compliable/sideload.rb', line 13 def polymorphic @polymorphic end |
#polymorphic_groups ⇒ Hash (readonly)
The subgroups, when polymorphic
13 14 15 |
# File 'lib/jsonapi_compliable/sideload.rb', line 13 def polymorphic_groups @polymorphic_groups end |
#primary_key ⇒ Symbol (readonly)
The attribute used to match objects - need not be a true database primary key.
13 14 15 |
# File 'lib/jsonapi_compliable/sideload.rb', line 13 def primary_key @primary_key end |
#resource_class ⇒ Class (readonly)
The corresponding Resource class
13 14 15 |
# File 'lib/jsonapi_compliable/sideload.rb', line 13 def resource_class @resource_class end |
#scope_proc ⇒ Proc (readonly)
The configured 'scope' block
13 14 15 |
# File 'lib/jsonapi_compliable/sideload.rb', line 13 def scope_proc @scope_proc end |
#sideloads ⇒ Hash (readonly)
The associated sibling sideloads
13 14 15 |
# File 'lib/jsonapi_compliable/sideload.rb', line 13 def sideloads @sideloads end |
#type ⇒ Symbol (readonly)
One of :has_many, :belongs_to, etc
13 14 15 |
# File 'lib/jsonapi_compliable/sideload.rb', line 13 def type @type end |
Instance Method Details
#after_save(only: [], except: [], &blk) ⇒ Object
Configure post-processing hooks
In particular, helpful for bulk operations. “after_save” will fire for any
persistence method - :create
, :update
,
:destroy
, :disassociate
. Use “only” and “except”
keyword arguments to fire only for a specific persistence method.
217 218 219 220 221 222 223 224 |
# File 'lib/jsonapi_compliable/sideload.rb', line 217 def after_save(only: [], except: [], &blk) actions = HOOK_ACTIONS - except actions = only & actions actions = [:save] if only.empty? && except.empty? actions.each do |a| hooks[:after_#{a}"] << blk end end |
#all_sideloads ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
333 334 335 336 337 338 339 340 341 342 343 |
# File 'lib/jsonapi_compliable/sideload.rb', line 333 def all_sideloads {}.tap do |all| if polymorphic? polymorphic_groups.each_pair do |type, sl| all.merge!(sl.resource.sideloading.all_sideloads) end else all.merge!(@sideloads.merge(resource.sideloading.sideloads)) end end end |
#allow_sideload(name, opts = {}, &blk) ⇒ Object
Configure a relationship between Resource objects
You probably want to extract this logic into an adapter rather than using directly
313 314 315 316 317 318 319 320 321 322 |
# File 'lib/jsonapi_compliable/sideload.rb', line 313 def allow_sideload(name, opts = {}, &blk) sideload = Sideload.new(name, opts) sideload.instance_eval(&blk) if blk if polymorphic? @polymorphic_groups[name] = sideload else @sideloads[name] = sideload end end |
#assign {|parents, children| ... } ⇒ Object
The proc used to assign the resolved parents and children.
You probably want to wrap this logic in an Adapter, instead of specifying in your resource directly.
168 169 170 |
# File 'lib/jsonapi_compliable/sideload.rb', line 168 def assign(&blk) @assign_proc = blk end |
#associate(parent, child) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Configure how to associate parent and child records. Delegates to #resource
178 179 180 181 |
# File 'lib/jsonapi_compliable/sideload.rb', line 178 def associate(parent, child) association_name = @parent ? @parent.name : name resource.associate(parent, child, association_name, type) end |
#association_names(memo = []) ⇒ Object
345 346 347 348 349 350 351 352 353 354 |
# File 'lib/jsonapi_compliable/sideload.rb', line 345 def association_names(memo = []) all_sideloads.each_pair do |name, sl| unless memo.include?(sl.name) memo << sl.name memo |= sl.association_names(memo) end end memo end |
#disassociate(parent, child) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Configure how to disassociate parent and child records. Delegates to #resource
189 190 191 192 |
# File 'lib/jsonapi_compliable/sideload.rb', line 189 def disassociate(parent, child) association_name = @parent ? @parent.name : name resource.disassociate(parent, child, association_name, type) end |
#fire_hooks!(parent, objects, method) ⇒ Object
363 364 365 366 367 368 369 370 |
# File 'lib/jsonapi_compliable/sideload.rb', line 363 def fire_hooks!(parent, objects, method) return unless self.hooks hooks = self.hooks[:after_#{method}"] + self.hooks[:after_save] hooks.compact.each do |hook| resource.instance_exec(parent, objects, &hook) end end |
#group_by(grouping_field) ⇒ Object
Define an attribute that groups the parent records. For instance, with an
ActiveRecord polymorphic belongs_to there will be a parent_id
and parent_type
. We would want to group on
parent_type
:
allow_sideload :organization, polymorphic: true do
# group parent_type, parent here is 'organization'
group_by :organization_type
end
248 249 250 |
# File 'lib/jsonapi_compliable/sideload.rb', line 248 def group_by(grouping_field) @grouping_field = grouping_field end |
#hooks ⇒ Object
Get the hooks the user has configured
229 230 231 232 233 234 235 236 |
# File 'lib/jsonapi_compliable/sideload.rb', line 229 def hooks @hooks ||= {}.tap do |h| HOOK_ACTIONS.each do |a| h[:after_#{a}"] = [] h[:before_#{a}"] = [] end end end |
#polymorphic? ⇒ Boolean
Is this sideload polymorphic?
Polymorphic sideloads group the parent objects in some fashion, so
different 'types' can be resolved differently. Let's say an
Office
has a polymorphic Organization
, which can
be either a Business
or Government
:
allow_sideload :organization, :polymorphic: true do
group_by :organization_type
allow_sideload 'Business', resource: BusinessResource do
# ... code ...
end
allow_sideload 'Governemnt', resource: GovernmentResource do
# ... code ...
end
end
You probably want to extract this code into an Adapter. For instance, with ActiveRecord:
polymorphic_belongs_to :organization,
group_by: :organization_type,
groups: {
'Business' => {
scope: -> { Business.all },
resource: BusinessResource,
foreign_key: :organization_id
},
'Government' => {
scope: -> { Government.all },
resource: GovernmentResource,
foreign_key: :organization_id
}
}
91 92 93 |
# File 'lib/jsonapi_compliable/sideload.rb', line 91 def polymorphic? @polymorphic == true end |
#polymorphic_child_for_type(type) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
357 358 359 360 361 |
# File 'lib/jsonapi_compliable/sideload.rb', line 357 def polymorphic_child_for_type(type) polymorphic_groups.values.find do |v| v.resource_class.config[:type] == type.to_sym end end |
#resolve(parents, query, namespace) ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Resolve the sideload.
-
Uses the 'scope' proc to build a 'base scope'
-
Chains additional criteria onto that 'base scope'
-
Resolves that scope (see Scope#resolve)
-
Assigns the resulting child objects to their corresponding parents
267 268 269 270 271 272 273 |
# File 'lib/jsonapi_compliable/sideload.rb', line 267 def resolve(parents, query, namespace) if polymorphic? resolve_polymorphic(parents, query) else resolve_basic(parents, query, namespace) end end |
#resource ⇒ Resource
Returns an instance of #resource_class
48 49 50 |
# File 'lib/jsonapi_compliable/sideload.rb', line 48 def resource @resource ||= resource_class.new end |
#scope {|parents| ... } ⇒ Object
Build a scope that will be used to fetch the related records This scope will be further chained with filtering/sorting/etc
You probably want to wrap this logic in an Adapter, instead of specifying in your resource directly.
131 132 133 |
# File 'lib/jsonapi_compliable/sideload.rb', line 131 def scope(&blk) @scope_proc = blk end |
#sideload(name) ⇒ Object
Fetch a Sideload object by its name
328 329 330 |
# File 'lib/jsonapi_compliable/sideload.rb', line 328 def sideload(name) @sideloads[name] end |