Class: Protip::Resource::Associations::BelongsToPolymorphicAssociation
- Inherits:
-
Object
- Object
- Protip::Resource::Associations::BelongsToPolymorphicAssociation
- Includes:
- Association
- Defined in:
- lib/protip/resource/associations/belongs_to_polymorphic_association.rb
Instance Attribute Summary collapse
-
#association_name ⇒ Object
readonly
Returns the value of attribute association_name.
-
#id_field ⇒ Object
readonly
Returns the value of attribute id_field.
-
#resource_class ⇒ Object
readonly
Returns the value of attribute resource_class.
Instance Method Summary collapse
-
#initialize(resource_class, association_name, nested_associations, id_field: nil) ⇒ BelongsToPolymorphicAssociation
constructor
Define a polymorphic association based on a one-of field.
- #read(resource) ⇒ Object
- #write(resource, value) ⇒ Object
Methods included from Association
Constructor Details
#initialize(resource_class, association_name, nested_associations, id_field: nil) ⇒ BelongsToPolymorphicAssociation
Define a polymorphic association based on a one-of field. The options for the oneof must all be IDs with an associated Protip::Resource::Associations::BelongsToAssociation that’s already been created.
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/protip/resource/associations/belongs_to_polymorphic_association.rb', line 21 def initialize(resource_class, association_name, nested_associations, id_field: nil) # The class where accessors will be defined @resource_class = resource_class # The name of the accessor methods @association_name = association_name.to_sym # The oneof field that holds the ID of the foreign resource @id_field = (id_field || Protip::Resource::Associations::BelongsToAssociation.default_id_field(association_name)).to_sym @oneof = @resource_class..descriptor.lookup_oneof(@id_field.to_s) raise "Invalid field name for polymorphic association: #{@id_field}" unless @oneof # Internally, keep the nested associations indexed by ID field @_nested_associations = {} nested_associations.each do |association| if @_nested_associations.has_key? association.id_field.to_sym raise ArgumentError.new("Duplicate association for #{id_field}") end @_nested_associations[association.id_field.to_sym] = association end field_names = @oneof.map{|desc| desc.name.to_sym} unless (field_names.length == @_nested_associations.length && @_nested_associations.keys.all?{|id_field| field_names.include? id_field}) raise ArgumentError.new( 'Polymorphic association requires an association to be defined for all nested fields' ) end end |
Instance Attribute Details
#association_name ⇒ Object (readonly)
Returns the value of attribute association_name.
10 11 12 |
# File 'lib/protip/resource/associations/belongs_to_polymorphic_association.rb', line 10 def association_name @association_name end |
#id_field ⇒ Object (readonly)
Returns the value of attribute id_field.
10 11 12 |
# File 'lib/protip/resource/associations/belongs_to_polymorphic_association.rb', line 10 def id_field @id_field end |
#resource_class ⇒ Object (readonly)
Returns the value of attribute resource_class.
10 11 12 |
# File 'lib/protip/resource/associations/belongs_to_polymorphic_association.rb', line 10 def resource_class @resource_class end |
Instance Method Details
#read(resource) ⇒ Object
51 52 53 54 55 56 57 58 |
# File 'lib/protip/resource/associations/belongs_to_polymorphic_association.rb', line 51 def read(resource) field = resource..public_send(id_field) if field @_nested_associations[field].read(resource) else nil end end |
#write(resource, value) ⇒ Object
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/protip/resource/associations/belongs_to_polymorphic_association.rb', line 60 def write(resource, value) if value == nil @oneof.each do |field_descriptor| resource.public_send(:"#{field_descriptor.name}=", nil) end nil else # Find the nested reference matching this association type matching_references = @_nested_associations.select do |id_field, reference| value.is_a? reference.associated_resource_class end # Make sure we found exactly one if matching_references.empty? raise ArgumentError.new("Could not find matching reference for value of type #{value.class}") end if matching_references.length > 1 raise ArgumentError.new( "Value of type #{value.class} matched with #{matching_references.keys.map(&:to_s).join(', ')}" ) end # And forward the write operation matching_references.values.first.write(resource, value) end end |