lib/jsonapi/relationship.rb in jsonapi-resources-0.10.7 vs lib/jsonapi/relationship.rb in jsonapi-resources-0.11.0.beta2
- old
+ new
@@ -1,11 +1,13 @@
+# frozen_string_literal: true
+
module JSONAPI
class Relationship
attr_reader :acts_as_set, :foreign_key, :options, :name,
- :class_name, :polymorphic, :always_include_optional_linkage_data,
+ :class_name, :polymorphic, :always_include_optional_linkage_data, :exclude_linkage_data,
:parent_resource, :eager_load_on_include, :custom_methods,
- :inverse_relationship, :allow_include, :use_related_resource_records_for_joins
+ :inverse_relationship, :allow_include, :hidden, :use_related_resource_records_for_joins
attr_writer :allow_include
attr_accessor :_routed, :_warned_missing_route
@@ -13,11 +15,11 @@
@name = name.to_s
@options = options
@acts_as_set = options.fetch(:acts_as_set, false) == true
@foreign_key = options[:foreign_key] ? options[:foreign_key].to_sym : nil
@parent_resource = options[:parent_resource]
- @relation_name = options.fetch(:relation_name, @name)
+ @relation_name = options[:relation_name]
@polymorphic = options.fetch(:polymorphic, false) == true
@polymorphic_types = options[:polymorphic_types]
if options[:polymorphic_relations]
ActiveSupport::Deprecation.warn('Use polymorphic_types instead of polymorphic_relations')
@polymorphic_types ||= options[:polymorphic_relations]
@@ -26,20 +28,24 @@
use_related_resource_records_for_joins_default = if options[:relation_name]
false
else
JSONAPI.configuration.use_related_resource_records_for_joins
end
-
+
@use_related_resource_records_for_joins = options.fetch(:use_related_resource_records_for_joins,
use_related_resource_records_for_joins_default) == true
+ @hidden = options.fetch(:hidden, false) == true
+
+ @exclude_linkage_data = options[:exclude_linkage_data]
@always_include_optional_linkage_data = options.fetch(:always_include_optional_linkage_data, false) == true
- @eager_load_on_include = options.fetch(:eager_load_on_include, false) == true
+ @eager_load_on_include = options.fetch(:eager_load_on_include, true) == true
@allow_include = options[:allow_include]
@class_name = nil
- @inverse_relationship = nil
+ @inverse_relationship = options[:inverse_relationship]&.to_sym
+
@_routed = false
@_warned_missing_route = false
exclude_links(options.fetch(:exclude_links, JSONAPI.configuration.default_exclude_links))
@@ -64,46 +70,60 @@
# :nocov:
@table_name ||= resource_klass._table_name
# :nocov:
end
+ def inverse_relationship
+ unless @inverse_relationship
+ @inverse_relationship ||= if resource_klass._relationship(@parent_resource._type.to_s.singularize).present?
+ @parent_resource._type.to_s.singularize.to_sym
+ elsif resource_klass._relationship(@parent_resource._type).present?
+ @parent_resource._type.to_sym
+ else
+ nil
+ end
+ end
+
+ @inverse_relationship
+ end
+
def self.polymorphic_types(name)
@poly_hash ||= {}.tap do |hash|
ObjectSpace.each_object do |klass|
next unless Module === klass
if ActiveRecord::Base > klass
- klass.reflect_on_all_associations(:has_many).select{|r| r.options[:as] }.each do |reflection|
+ klass.reflect_on_all_associations(:has_many).select { |r| r.options[:as] }.each do |reflection|
(hash[reflection.options[:as]] ||= []) << klass.name.underscore
end
end
end
end
@poly_hash[name.to_sym]
end
def resource_types
if polymorphic? && belongs_to?
- @polymorphic_types ||= self.class.polymorphic_types(@relation_name).collect {|t| t.pluralize}
+ @polymorphic_types ||= self.class.polymorphic_types(_relation_name).collect { |t| t.pluralize }
else
[resource_klass._type.to_s.pluralize]
end
end
def type
@type ||= resource_klass._type.to_sym
end
def relation_name(options)
- case @relation_name
- when Symbol
- # :nocov:
- @relation_name
- # :nocov:
- when String
- @relation_name.to_sym
- when Proc
- @relation_name.call(options)
+ case _relation_name
+ when Symbol
+ # :nocov:
+ _relation_name
+ # :nocov:
+ when String
+ _relation_name.to_sym
+ when Proc
+ _relation_name.call(options)
end
end
def belongs_to?
# :nocov:
@@ -115,18 +135,18 @@
@options[:readonly]
end
def exclude_links(exclude)
case exclude
- when :default, "default"
- @_exclude_links = [:self, :related]
- when :none, "none"
- @_exclude_links = []
- when Array
- @_exclude_links = exclude.collect {|link| link.to_sym}
- else
- fail "Invalid exclude_links"
+ when :default, "default"
+ @_exclude_links = [:self, :related]
+ when :none, "none"
+ @_exclude_links = []
+ when Array
+ @_exclude_links = exclude.collect { |link| link.to_sym }
+ else
+ fail "Invalid exclude_links"
end
end
def _exclude_links
@_exclude_links ||= []
@@ -134,21 +154,32 @@
def exclude_link?(link)
_exclude_links.include?(link.to_sym)
end
+ def _relation_name
+ @relation_name || @name
+ end
+
class ToOne < Relationship
attr_reader :foreign_key_on
def initialize(name, options = {})
super
@class_name = options.fetch(:class_name, name.to_s.camelize)
@foreign_key ||= "#{name}_id".to_sym
@foreign_key_on = options.fetch(:foreign_key_on, :self)
- if parent_resource
- @inverse_relationship = options.fetch(:inverse_relationship, parent_resource._type)
+ # if parent_resource
+ # @inverse_relationship = options.fetch(:inverse_relationship, parent_resource._type)
+ # end
+
+ if options.fetch(:create_implicit_polymorphic_type_relationships, true) == true && polymorphic?
+ # Setup the implicit relationships for the polymorphic types and exclude linkage data
+ setup_implicit_relationships_for_polymorphic_types
end
+
+ @polymorphic_type_relationship_for = options[:polymorphic_type_relationship_for]
end
def to_s
# :nocov: useful for debugging
"#{parent_resource}.#{name}(#{belongs_to? ? 'BelongsToOne' : 'ToOne'})"
@@ -159,29 +190,48 @@
# :nocov:
foreign_key_on == :self
# :nocov:
end
+ def hidden?
+ @hidden || @polymorphic_type_relationship_for.present?
+ end
+
def polymorphic_type
"#{name}_type" if polymorphic?
end
+ def setup_implicit_relationships_for_polymorphic_types(exclude_linkage_data: true)
+ types = self.class.polymorphic_types(_relation_name)
+ unless types.present?
+ warn "No polymorphic types found for #{parent_resource.name} #{_relation_name}"
+ return
+ end
+
+ types.each do |type|
+ parent_resource.has_one(type.to_s.underscore.singularize,
+ exclude_linkage_data: exclude_linkage_data,
+ polymorphic_type_relationship_for: name)
+ end
+ end
+
def include_optional_linkage_data?
+ return false if @exclude_linkage_data
@always_include_optional_linkage_data || JSONAPI::configuration.always_include_to_one_linkage_data
end
def allow_include?(context = nil)
strategy = if @allow_include.nil?
JSONAPI.configuration.default_allow_include_to_one
else
@allow_include
end
- if !!strategy == strategy #check for boolean
+ if !!strategy == strategy # check for boolean
return strategy
elsif strategy.is_a?(Symbol) || strategy.is_a?(String)
- parent_resource.send(strategy, context)
+ parent_resource_klass.send(strategy, context)
else
strategy.call(context)
end
end
end
@@ -192,21 +242,25 @@
def initialize(name, options = {})
super
@class_name = options.fetch(:class_name, name.to_s.camelize.singularize)
@foreign_key ||= "#{name.to_s.singularize}_ids".to_sym
@reflect = options.fetch(:reflect, true) == true
- if parent_resource
- @inverse_relationship = options.fetch(:inverse_relationship, parent_resource._type.to_s.singularize.to_sym)
- end
+ # if parent_resource
+ # @inverse_relationship = options.fetch(:inverse_relationship, parent_resource._type.to_s.singularize.to_sym)
+ # end
end
def to_s
# :nocov: useful for debugging
- "#{parent_resource}.#{name}(ToMany)"
+ "#{parent_resource_klass}.#{name}(ToMany)"
# :nocov:
end
+ def hidden?
+ @hidden
+ end
+
def include_optional_linkage_data?
# :nocov:
@always_include_optional_linkage_data || JSONAPI::configuration.always_include_to_many_linkage_data
# :nocov:
end
@@ -216,13 +270,13 @@
JSONAPI.configuration.default_allow_include_to_many
else
@allow_include
end
- if !!strategy == strategy #check for boolean
+ if !!strategy == strategy # check for boolean
return strategy
elsif strategy.is_a?(Symbol) || strategy.is_a?(String)
- parent_resource.send(strategy, context)
+ parent_resource_klass.send(strategy, context)
else
strategy.call(context)
end
end