Class: JSONAPI::Resource

Inherits:
Object
  • Object
show all
Includes:
Callbacks
Defined in:
lib/jsonapi/resource.rb

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Callbacks

included

Constructor Details

#initialize(model, context) ⇒ Resource

Returns a new instance of Resource.



22
23
24
25
# File 'lib/jsonapi/resource.rb', line 22

def initialize(model, context)
  @model = model
  @context = context
end

Class Attribute Details

._allowed_filtersObject

Returns the value of attribute _allowed_filters.



332
333
334
# File 'lib/jsonapi/resource.rb', line 332

def _allowed_filters
  @_allowed_filters
end

._attributesObject

Returns the value of attribute _attributes.



332
333
334
# File 'lib/jsonapi/resource.rb', line 332

def _attributes
  @_attributes
end

._model_hintsObject

Returns the value of attribute _model_hints.



332
333
334
# File 'lib/jsonapi/resource.rb', line 332

def _model_hints
  @_model_hints
end

._paginatorObject

Returns the value of attribute _paginator.



332
333
334
# File 'lib/jsonapi/resource.rb', line 332

def _paginator
  @_paginator
end

._relationshipsObject

Returns the value of attribute _relationships.



332
333
334
# File 'lib/jsonapi/resource.rb', line 332

def _relationships
  @_relationships
end

._typeObject

Returns the value of attribute _type.



332
333
334
# File 'lib/jsonapi/resource.rb', line 332

def _type
  @_type
end

Instance Attribute Details

#contextObject (readonly)

Returns the value of attribute context.



7
8
9
# File 'lib/jsonapi/resource.rb', line 7

def context
  @context
end

Class Method Details

._abstractObject



719
720
721
# File 'lib/jsonapi/resource.rb', line 719

def _abstract
  @abstract
end

._add_relationship(klass, *attrs) ⇒ Object



765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
# File 'lib/jsonapi/resource.rb', line 765

def _add_relationship(klass, *attrs)
  options = attrs.extract_options!
  options[:parent_resource] = self

  attrs.each do |attr|
    relationship_name = attr.to_sym

    check_reserved_relationship_name(relationship_name)

    # Initialize from an ActiveRecord model's properties
    if _model_class && _model_class.ancestors.collect{|ancestor| ancestor.name}.include?('ActiveRecord::Base')
      model_association = _model_class.reflect_on_association(relationship_name)
      if model_association
        options[:class_name] ||= model_association.class_name
      end
    end

    @_relationships[relationship_name] = relationship = klass.new(relationship_name, options)

    associated_records_method_name = case relationship
                                     when JSONAPI::Relationship::ToOne then "record_for_#{relationship_name}"
                                     when JSONAPI::Relationship::ToMany then "records_for_#{relationship_name}"
                                     end

    foreign_key = relationship.foreign_key

    define_method "#{foreign_key}=" do |value|
      @model.method("#{foreign_key}=").call(value)
    end unless method_defined?("#{foreign_key}=")

    define_method associated_records_method_name do
      relationship = self.class._relationships[relationship_name]
      relation_name = relationship.relation_name(context: @context)
      records_for(relation_name)
    end unless method_defined?(associated_records_method_name)

    if relationship.is_a?(JSONAPI::Relationship::ToOne)
      if relationship.belongs_to?
        define_method foreign_key do
          @model.method(foreign_key).call
        end unless method_defined?(foreign_key)

        define_method relationship_name do |options = {}|
          relationship = self.class._relationships[relationship_name]

          if relationship.polymorphic?
            associated_model = public_send(associated_records_method_name)
            resource_klass = self.class.resource_for_model(associated_model) if associated_model
            return resource_klass.new(associated_model, @context) if resource_klass
          else
            resource_klass = relationship.resource_klass
            if resource_klass
              associated_model = public_send(associated_records_method_name)
              return associated_model ? resource_klass.new(associated_model, @context) : nil
            end
          end
        end unless method_defined?(relationship_name)
      else
        define_method foreign_key do
          relationship = self.class._relationships[relationship_name]

          record = public_send(associated_records_method_name)
          return nil if record.nil?
          record.public_send(relationship.resource_klass._primary_key)
        end unless method_defined?(foreign_key)

        define_method relationship_name do |options = {}|
          relationship = self.class._relationships[relationship_name]

          resource_klass = relationship.resource_klass
          if resource_klass
            associated_model = public_send(associated_records_method_name)
            return associated_model ? resource_klass.new(associated_model, @context) : nil
          end
        end unless method_defined?(relationship_name)
      end
    elsif relationship.is_a?(JSONAPI::Relationship::ToMany)
      define_method foreign_key do
        records = public_send(associated_records_method_name)
        return records.collect do |record|
          record.public_send(relationship.resource_klass._primary_key)
        end
      end unless method_defined?(foreign_key)

      define_method relationship_name do |options = {}|
        relationship = self.class._relationships[relationship_name]

        resource_klass = relationship.resource_klass
        records = public_send(associated_records_method_name)

        filters = options.fetch(:filters, {})
        unless filters.nil? || filters.empty?
          records = resource_klass.apply_filters(records, filters, options)
        end

        sort_criteria =  options.fetch(:sort_criteria, {})
        unless sort_criteria.nil? || sort_criteria.empty?
          order_options = relationship.resource_klass.construct_order_options(sort_criteria)
          records = resource_klass.apply_sort(records, order_options, @context)
        end

        paginator = options[:paginator]
        if paginator
          records = resource_klass.apply_pagination(records, paginator, order_options)
        end

        return records.collect do |record|
          if relationship.polymorphic?
            resource_klass = self.class.resource_for_model(record)
          end
          resource_klass.new(record, @context)
        end
      end unless method_defined?(relationship_name)
    end
  end
end

._allowed_filter?(filter) ⇒ Boolean

Returns:

  • (Boolean)


744
745
746
# File 'lib/jsonapi/resource.rb', line 744

def _allowed_filter?(filter)
  !_allowed_filters[filter].nil?
end

._as_parent_keyObject



699
700
701
# File 'lib/jsonapi/resource.rb', line 699

def _as_parent_key
  @_as_parent_key ||= "#{_type.to_s.singularize}_id"
end

._attribute_options(attr) ⇒ Object

quasi private class methods



678
679
680
# File 'lib/jsonapi/resource.rb', line 678

def _attribute_options(attr)
  default_attribute_options.merge(@_attributes[attr])
end

._immutableObject



727
728
729
# File 'lib/jsonapi/resource.rb', line 727

def _immutable
  @immutable
end

._model_classObject



735
736
737
738
739
740
741
742
# File 'lib/jsonapi/resource.rb', line 735

def _model_class
  return nil if _abstract

  return @model if @model
  @model = _model_name.to_s.safe_constantize
  warn "[MODEL NOT FOUND] Model could not be found for #{self.name}. If this a base Resource declare it as abstract." if @model.nil?
  @model
end

._model_nameObject



691
692
693
# File 'lib/jsonapi/resource.rb', line 691

def _model_name
  _abstract ? '' : @_model_name ||= name.demodulize.sub(/Resource$/, '')
end

._primary_keyObject



695
696
697
# File 'lib/jsonapi/resource.rb', line 695

def _primary_key
  @_primary_key ||= _model_class.respond_to?(:primary_key) ? _model_class.primary_key : :id
end

._relationship(type) ⇒ Object



686
687
688
689
# File 'lib/jsonapi/resource.rb', line 686

def _relationship(type)
  type = type.to_sym
  @_relationships[type]
end

._resource_name_from_type(type) ⇒ Object



319
320
321
# File 'lib/jsonapi/resource.rb', line 319

def _resource_name_from_type(type)
  "#{type.to_s.underscore.singularize}_resource".camelize
end

._updatable_relationshipsObject



682
683
684
# File 'lib/jsonapi/resource.rb', line 682

def _updatable_relationships
  @_relationships.map { |key, _relationship| key }
end

.abstract(val = true) ⇒ Object



715
716
717
# File 'lib/jsonapi/resource.rb', line 715

def abstract(val = true)
  @abstract = val
end

.apply_filter(records, filter, value, options = {}) ⇒ Object



510
511
512
513
514
515
516
517
518
# File 'lib/jsonapi/resource.rb', line 510

def apply_filter(records, filter, value, options = {})
  strategy = _allowed_filters.fetch(filter.to_sym, Hash.new)[:apply]

  if strategy
    strategy.call(records, value, options)
  else
    records.where(filter => value)
  end
end

.apply_filters(records, filters, options = {}) ⇒ Object



520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
# File 'lib/jsonapi/resource.rb', line 520

def apply_filters(records, filters, options = {})
  required_includes = []

  if filters
    filters.each do |filter, value|
      if _relationships.include?(filter)
        if _relationships[filter].is_a?(JSONAPI::Relationship::ToMany)
          required_includes.push(filter.to_s)
          records = apply_filter(records, "#{filter}.#{_relationships[filter].primary_key}", value, options)
        else
          records = apply_filter(records, "#{_relationships[filter].foreign_key}", value, options)
        end
      else
        records = apply_filter(records, filter, value, options)
      end
    end
  end

  if required_includes.any?
    records = apply_includes(records, options.merge(include_directives: IncludeDirectives.new(required_includes)))
  end

  records
end

.apply_includes(records, options = {}) ⇒ Object



487
488
489
490
491
492
493
494
495
# File 'lib/jsonapi/resource.rb', line 487

def apply_includes(records, options = {})
  include_directives = options[:include_directives]
  if include_directives
    model_includes = resolve_relationship_names_to_relations(self, include_directives.model_includes, options)
    records = records.includes(model_includes)
  end

  records
end

.apply_pagination(records, paginator, order_options) ⇒ Object



497
498
499
500
# File 'lib/jsonapi/resource.rb', line 497

def apply_pagination(records, paginator, order_options)
  records = paginator.apply(records, order_options) if paginator
  records
end

.apply_sort(records, order_options, _context = {}) ⇒ Object



502
503
504
505
506
507
508
# File 'lib/jsonapi/resource.rb', line 502

def apply_sort(records, order_options, _context = {})
  if order_options.any?
    records.order(order_options)
  else
    records
  end
end

.attribute(attr, options = {}) ⇒ Object



358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
# File 'lib/jsonapi/resource.rb', line 358

def attribute(attr, options = {})
  check_reserved_attribute_name(attr)

  if (attr.to_sym == :id) && (options[:format].nil?)
    ActiveSupport::Deprecation.warn('Id without format is no longer supported. Please remove ids from attributes, or specify a format.')
  end

  @_attributes ||= {}
  @_attributes[attr] = options
  define_method attr do
    @model.public_send(attr)
  end unless method_defined?(attr)

  define_method "#{attr}=" do |value|
    @model.public_send "#{attr}=", value
  end unless method_defined?("#{attr}=")
end

.attributes(*attrs) ⇒ Object

Methods used in defining a resource class



351
352
353
354
355
356
# File 'lib/jsonapi/resource.rb', line 351

def attributes(*attrs)
  options = attrs.extract_options!.dup
  attrs.each do |attr|
    attribute(attr, options)
  end
end

.construct_order_options(sort_params) ⇒ Object



756
757
758
759
760
761
762
763
# File 'lib/jsonapi/resource.rb', line 756

def construct_order_options(sort_params)
  return {} unless sort_params

  sort_params.each_with_object({}) do |sort, order_hash|
    field = sort[:field] == 'id' ? _primary_key : sort[:field]
    order_hash[field] = sort[:direction]
  end
end

.creatable_fields(_context = nil) ⇒ Object

Override in your resource to filter the creatable keys



454
455
456
# File 'lib/jsonapi/resource.rb', line 454

def creatable_fields(_context = nil)
  _updatable_relationships | _attributes.keys
end

.create(context) ⇒ Object



334
335
336
# File 'lib/jsonapi/resource.rb', line 334

def create(context)
  new(create_model, context)
end

.create_modelObject



338
339
340
# File 'lib/jsonapi/resource.rb', line 338

def create_model
  _model_class.new
end

.default_attribute_optionsObject



376
377
378
# File 'lib/jsonapi/resource.rb', line 376

def default_attribute_options
  { format: :default }
end

.fetchable_fields(_context = nil) ⇒ Object

Override in your resource to filter the fetchable keys



444
445
446
# File 'lib/jsonapi/resource.rb', line 444

def fetchable_fields(_context = nil)
  fields
end

.fieldsObject



463
464
465
# File 'lib/jsonapi/resource.rb', line 463

def fields
  _relationships.keys | _attributes.keys
end

.filter(attr, *args) ⇒ Object



420
421
422
# File 'lib/jsonapi/resource.rb', line 420

def filter(attr, *args)
  @_allowed_filters[attr.to_sym] = args.extract_options!
end

.filter_records(filters, options, records = records(options)) ⇒ Object



545
546
547
548
# File 'lib/jsonapi/resource.rb', line 545

def filter_records(filters, options, records = records(options))
  records = apply_filters(records, filters, options)
  apply_includes(records, options)
end

.filters(*attrs) ⇒ Object



416
417
418
# File 'lib/jsonapi/resource.rb', line 416

def filters(*attrs)
  @_allowed_filters.merge!(attrs.inject({}) { |h, attr| h[attr] = {}; h })
end

.find(filters, options = {}) ⇒ Object

Override this method if you have more complex requirements than this basic find method provides



559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
# File 'lib/jsonapi/resource.rb', line 559

def find(filters, options = {})
  context = options[:context]

  records = filter_records(filters, options)

  sort_criteria = options.fetch(:sort_criteria) { [] }
  order_options = construct_order_options(sort_criteria)
  records = sort_records(records, order_options, context)

  records = apply_pagination(records, options[:paginator], order_options)

  resources = []
  records.each do |model|
    resources.push self.resource_for_model(model).new(model, context)
  end

  resources
end

.find_by_key(key, options = {}) ⇒ Object



578
579
580
581
582
583
584
585
# File 'lib/jsonapi/resource.rb', line 578

def find_by_key(key, options = {})
  context = options[:context]
  records = records(options)
  records = apply_includes(records, options)
  model = records.where({_primary_key => key}).first
  fail JSONAPI::Exceptions::RecordNotFound.new(key) if model.nil?
  self.resource_for_model(model).new(model, context)
end

.find_count(filters, options = {}) ⇒ Object



554
555
556
# File 'lib/jsonapi/resource.rb', line 554

def find_count(filters, options = {})
  filter_records(filters, options).count(:all)
end

.has_many(*attrs) ⇒ Object



399
400
401
# File 'lib/jsonapi/resource.rb', line 399

def has_many(*attrs)
  _add_relationship(Relationship::ToMany, *attrs)
end

.has_one(*attrs) ⇒ Object



395
396
397
# File 'lib/jsonapi/resource.rb', line 395

def has_one(*attrs)
  _add_relationship(Relationship::ToOne, *attrs)
end

.immutable(val = true) ⇒ Object



723
724
725
# File 'lib/jsonapi/resource.rb', line 723

def immutable(val = true)
  @immutable = val
end

.inherited(subclass) ⇒ Object



278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
# File 'lib/jsonapi/resource.rb', line 278

def inherited(subclass)
  subclass.abstract(false)
  subclass.immutable(false)
  subclass._attributes = (_attributes || {}).dup
  subclass._model_hints = (_model_hints || {}).dup

  subclass._relationships = {}
  # Add the relationships from the base class to the subclass using the original options
  if _relationships.is_a?(Hash)
    _relationships.each_value do |relationship|
      options = relationship.options.dup
      options[:parent_resource] = subclass
      subclass._add_relationship(relationship.class, relationship.name, options)
    end
  end

  subclass._allowed_filters = (_allowed_filters || Set.new).dup

  type = subclass.name.demodulize.sub(/Resource$/, '').underscore
  subclass._type = type.pluralize.to_sym

  subclass.attribute :id, format: :id

  check_reserved_resource_name(subclass._type, subclass.name)
end

.is_filter_relationship?(filter) ⇒ Boolean

Returns:

  • (Boolean)


602
603
604
# File 'lib/jsonapi/resource.rb', line 602

def is_filter_relationship?(filter)
  filter == _type || _relationships.include?(filter)
end

.key_type(key_type) ⇒ Object



623
624
625
# File 'lib/jsonapi/resource.rb', line 623

def key_type(key_type)
  @_resource_key_type = key_type
end

.method_missing(method, *args) ⇒ Object

TODO: remove this after the createable_fields and updateable_fields are phased out :nocov:



430
431
432
433
434
435
436
437
438
439
440
# File 'lib/jsonapi/resource.rb', line 430

def method_missing(method, *args)
  if method.to_s.match /createable_fields/
    ActiveSupport::Deprecation.warn('`createable_fields` is deprecated, please use `creatable_fields` instead')
    creatable_fields(*args)
  elsif method.to_s.match /updateable_fields/
    ActiveSupport::Deprecation.warn('`updateable_fields` is deprecated, please use `updatable_fields` instead')
    updatable_fields(*args)
  else
    super
  end
end

.model_hint(model: _model_name, resource: _type) ⇒ Object



409
410
411
412
413
414
# File 'lib/jsonapi/resource.rb', line 409

def model_hint(model: _model_name, resource: _type)
  model_name = ((model.is_a?(Class)) && (model < ActiveRecord::Base)) ? model.name : model
  resource_type = ((resource.is_a?(Class)) && (resource < JSONAPI::Resource)) ? resource._type : resource.to_s

  _model_hints[model_name.to_s.gsub('::', '/').underscore] = resource_type.to_s
end

.model_name(model, options = {}) ⇒ Object



403
404
405
406
407
# File 'lib/jsonapi/resource.rb', line 403

def model_name(model, options = {})
  @_model_name = model.to_sym

  model_hint(model: @_model_name, resource: self) unless options[:add_model_hint] == false
end

.module_pathObject



748
749
750
751
752
753
754
# File 'lib/jsonapi/resource.rb', line 748

def module_path
  if name == 'JSONAPI::Resource'
    ''
  else
    name =~ /::[^:]+\Z/ ? ($`.freeze.gsub('::', '/') + '/').underscore : ''
  end
end

.mutable?Boolean

Returns:

  • (Boolean)


731
732
733
# File 'lib/jsonapi/resource.rb', line 731

def mutable?
  !@immutable
end

.paginator(paginator) ⇒ Object



711
712
713
# File 'lib/jsonapi/resource.rb', line 711

def paginator(paginator)
  @_paginator = paginator
end

.primary_key(key) ⇒ Object



424
425
426
# File 'lib/jsonapi/resource.rb', line 424

def primary_key(key)
  @_primary_key = key.to_sym
end

.records(_options = {}) ⇒ Object

Override this method if you want to customize the relation for finder methods (find, find_by_key)



589
590
591
# File 'lib/jsonapi/resource.rb', line 589

def records(_options = {})
  _model_class
end

.relationship(*attrs) ⇒ Object



380
381
382
383
384
385
386
387
388
389
390
391
392
393
# File 'lib/jsonapi/resource.rb', line 380

def relationship(*attrs)
  options = attrs.extract_options!
  klass = case options[:to]
            when :one
              Relationship::ToOne
            when :many
              Relationship::ToMany
            else
              #:nocov:#
              fail ArgumentError.new('to: must be either :one or :many')
              #:nocov:#
          end
  _add_relationship(klass, *attrs, options.except(:to))
end

.resolve_relationship_names_to_relations(resource_klass, model_includes, options = {}) ⇒ Object



467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
# File 'lib/jsonapi/resource.rb', line 467

def resolve_relationship_names_to_relations(resource_klass, model_includes, options = {})
  case model_includes
    when Array
      return model_includes.map do |value|
        resolve_relationship_names_to_relations(resource_klass, value, options)
      end
    when Hash
      model_includes.keys.each do |key|
        relationship = resource_klass._relationships[key]
        value = model_includes[key]
        model_includes.delete(key)
        model_includes[relationship.relation_name(options)] = resolve_relationship_names_to_relations(relationship.resource_klass, value, options)
      end
      return model_includes
    when Symbol
      relationship = resource_klass._relationships[model_includes]
      return relationship.relation_name(options)
  end
end

.resource_for(type) ⇒ Object



304
305
306
307
308
309
310
311
312
313
# File 'lib/jsonapi/resource.rb', line 304

def resource_for(type)
  type_with_module = type.include?('/') ? type : module_path + type

  resource_name = _resource_name_from_type(type_with_module)
  resource = resource_name.safe_constantize if resource_name
  if resource.nil?
    fail NameError, "JSONAPI: Could not find resource '#{type}'. (Class #{resource_name} not found)"
  end
  resource
end

.resource_for_model(model) ⇒ Object



315
316
317
# File 'lib/jsonapi/resource.rb', line 315

def resource_for_model(model)
  resource_for(resource_type_for(model))
end

.resource_key_typeObject



627
628
629
# File 'lib/jsonapi/resource.rb', line 627

def resource_key_type
  @_resource_key_type || JSONAPI.configuration.resource_key_type
end

.resource_type_for(model) ⇒ Object



323
324
325
326
327
328
329
330
# File 'lib/jsonapi/resource.rb', line 323

def resource_type_for(model)
  model_name = model.class.to_s.underscore
  if _model_hints[model_name]
    _model_hints[model_name]
  else
    model_name.rpartition('/').last
  end
end

.routing_options(options) ⇒ Object



342
343
344
# File 'lib/jsonapi/resource.rb', line 342

def routing_options(options)
  @_routing_resource_options = options
end

.routing_resource_optionsObject



346
347
348
# File 'lib/jsonapi/resource.rb', line 346

def routing_resource_options
  @_routing_resource_options ||= {}
end

.sort_records(records, order_options, context = {}) ⇒ Object



550
551
552
# File 'lib/jsonapi/resource.rb', line 550

def sort_records(records, order_options, context = {})
  apply_sort(records, order_options, context)
end

.sortable_fields(_context = nil) ⇒ Object

Override in your resource to filter the sortable keys



459
460
461
# File 'lib/jsonapi/resource.rb', line 459

def sortable_fields(_context = nil)
  _attributes.keys
end

.updatable_fields(_context = nil) ⇒ Object

Override in your resource to filter the updatable keys



449
450
451
# File 'lib/jsonapi/resource.rb', line 449

def updatable_fields(_context = nil)
  _updatable_relationships | _attributes.keys - [:id]
end

.verify_custom_filter(filter, value, _context = nil) ⇒ Object

Either add a custom :verify labmda or override verify_custom_filter to allow for custom filters



667
668
669
# File 'lib/jsonapi/resource.rb', line 667

def verify_custom_filter(filter, value, _context = nil)
  [filter, value]
end

.verify_filter(filter, raw, context = nil) ⇒ Object



606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
# File 'lib/jsonapi/resource.rb', line 606

def verify_filter(filter, raw, context = nil)
  filter_values = []
  filter_values += CSV.parse_line(raw) unless raw.nil? || raw.empty?

  strategy = _allowed_filters.fetch(filter, Hash.new)[:verify]

  if strategy
    [filter, strategy.call(filter_values, context)]
  else
    if is_filter_relationship?(filter)
      verify_relationship_filter(filter, filter_values, context)
    else
      verify_custom_filter(filter, filter_values, context)
    end
  end
end

.verify_filters(filters, context = nil) ⇒ Object



593
594
595
596
597
598
599
600
# File 'lib/jsonapi/resource.rb', line 593

def verify_filters(filters, context = nil)
  verified_filters = {}
  filters.each do |filter, raw_value|
    verified_filter = verify_filter(filter, raw_value, context)
    verified_filters[verified_filter[0]] = verified_filter[1]
  end
  verified_filters
end

.verify_key(key, context = nil) ⇒ Object



631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
# File 'lib/jsonapi/resource.rb', line 631

def verify_key(key, context = nil)
  key_type = resource_key_type

  case key_type
  when :integer
    return if key.nil?
    Integer(key)
  when :string
    return if key.nil?
    if key.to_s.include?(',')
      raise JSONAPI::Exceptions::InvalidFieldValue.new(:id, key)
    else
      key
    end
  when :uuid
    return if key.nil?
    if key.to_s.match(/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/)
      key
    else
      raise JSONAPI::Exceptions::InvalidFieldValue.new(:id, key)
    end
  else
    key_type.call(key, context)
  end
rescue
  raise JSONAPI::Exceptions::InvalidFieldValue.new(:id, key)
end

.verify_keys(keys, context = nil) ⇒ Object

override to allow for key processing and checking



660
661
662
663
664
# File 'lib/jsonapi/resource.rb', line 660

def verify_keys(keys, context = nil)
  return keys.collect do |key|
    verify_key(key, context)
  end
end

.verify_relationship_filter(filter, raw, _context = nil) ⇒ Object

Either add a custom :verify labmda or override verify_relationship_filter to allow for custom relationship logic, such as uuids, multiple keys or permission checks on keys



673
674
675
# File 'lib/jsonapi/resource.rb', line 673

def verify_relationship_filter(filter, raw, _context = nil)
  [filter, raw]
end

Instance Method Details

#_modelObject



27
28
29
# File 'lib/jsonapi/resource.rb', line 27

def _model
  @model
end

#change(callback) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/jsonapi/resource.rb', line 39

def change(callback)
  completed = false

  if @changing
    run_callbacks callback do
      completed = (yield == :completed)
    end
  else
    run_callbacks is_new? ? :create : :update do
      @changing = true
      run_callbacks callback do
        completed = (yield == :completed)
      end

      completed = (save == :completed) if @save_needed || is_new?
    end
  end

  return completed ? :completed : :accepted
end


66
67
68
69
70
# File 'lib/jsonapi/resource.rb', line 66

def create_to_many_links(relationship_type, relationship_key_values)
  change :create_to_many_link do
    _create_to_many_links(relationship_type, relationship_key_values)
  end
end

#fetchable_fieldsObject



108
109
110
# File 'lib/jsonapi/resource.rb', line 108

def fetchable_fields
  self.class.fetchable_fields(context)
end

#idObject



31
32
33
# File 'lib/jsonapi/resource.rb', line 31

def id
  _model.public_send(self.class._primary_key)
end

#is_new?Boolean

Returns:

  • (Boolean)


35
36
37
# File 'lib/jsonapi/resource.rb', line 35

def is_new?
  id.nil?
end

#meta(_options) ⇒ Object

Override this to return resource level meta data must return a hash, and if the hash is empty the meta section will not be serialized with the resource meta keys will be not be formatted with the key formatter for the serializer by default. They can however use the serializer’s format_key and format_value methods if desired the _options hash will contain the serializer and the serialization_options



127
128
129
# File 'lib/jsonapi/resource.rb', line 127

def meta(_options)
  {}
end

#model_error_messagesObject



118
119
120
# File 'lib/jsonapi/resource.rb', line 118

def model_error_messages
  _model.errors.messages
end

#records_for(relation_name) ⇒ Object

Override this on a resource to customize how the associated records are fetched for a model. Particularly helpful for authorization.



114
115
116
# File 'lib/jsonapi/resource.rb', line 114

def records_for(relation_name)
  _model.public_send relation_name
end

#removeObject



60
61
62
63
64
# File 'lib/jsonapi/resource.rb', line 60

def remove
  run_callbacks :remove do
    _remove
  end
end


90
91
92
93
94
# File 'lib/jsonapi/resource.rb', line 90

def remove_to_many_link(relationship_type, key)
  change :remove_to_many_link do
    _remove_to_many_link(relationship_type, key)
  end
end


96
97
98
99
100
# File 'lib/jsonapi/resource.rb', line 96

def remove_to_one_link(relationship_type)
  change :remove_to_one_link do
    _remove_to_one_link(relationship_type)
  end
end

#replace_fields(field_data) ⇒ Object



102
103
104
105
106
# File 'lib/jsonapi/resource.rb', line 102

def replace_fields(field_data)
  change :replace_fields do
    _replace_fields(field_data)
  end
end


84
85
86
87
88
# File 'lib/jsonapi/resource.rb', line 84

def replace_polymorphic_to_one_link(relationship_type, relationship_key_value, relationship_key_type)
  change :replace_polymorphic_to_one_link do
    _replace_polymorphic_to_one_link(relationship_type, relationship_key_value, relationship_key_type)
  end
end


72
73
74
75
76
# File 'lib/jsonapi/resource.rb', line 72

def replace_to_many_links(relationship_type, relationship_key_values)
  change :replace_to_many_links do
    _replace_to_many_links(relationship_type, relationship_key_values)
  end
end


78
79
80
81
82
# File 'lib/jsonapi/resource.rb', line 78

def replace_to_one_link(relationship_type, relationship_key_value)
  change :replace_to_one_link do
    _replace_to_one_link(relationship_type, relationship_key_value)
  end
end