Class: SBF::Client::BaseEntity

Inherits:
Object
  • Object
show all
Extended by:
ActiveModel::Naming, ActiveModel::Translation
Includes:
ActiveModel::Conversion, ActiveModel::Dirty
Defined in:
lib/stbaldricks/entities/lib/base.rb

Direct Known Subclasses

Address, Api::Response, Campaign::Totals, Challenger::Totals, Diagnosis, Donation::EmployerMatching, Donation::RecognitionCard, Donation::RecognitionCard::Recipient, Donation::SBFGeneralFund, Donation::Tribute, EmailAddress, Event::Activity, Event::Agreement, Event::Agreement::Question, Event::CoachTracking, Event::CoachTracking::CoachingInteractions, Event::CoachTracking::Plaque, Event::CoachTracking::Proceeds, Event::Contacts, Event::Contacts::Contact, Event::Photos, Event::Totals, EventApplication::Requestor, FullInstitution, FullOrganization::ContactName, Fund::Photos, Fund::Totals, Fund::YearlyTotals, Fundraiser::Location, Fundraiser::Photos, Fundraiser::Policies, Fundraiser::Rankings, Fundraiser::Rankings::Ranking, Fundraiser::Totals, Fundraiser::Venue, FundraisingPage, GeoLocation, Grant::FullFundingType, Grant::FullResearcher, Grant::PartialFundingType, Grant::PartialResearcher, Guardian, InternationalPartner::Link, InternationalPartner::WebPage, Kid::Relationship, Kid::Relationship::Permissions, KidURL, Location, MatchingGift::Company::Contact, MatchingGift::Company::EmployeeEligibility, MatchingGift::Company::GiftRatio, MatchingGift::Company::Procedures, MatchingGift::Company::Requirements, MatchingGift::Company::Restrictions, Memorial::Photos, Memorial::Totals, Memorial::Tribute, Message::Recipient, NamePieces, NotImplementedObject, OptOutSettings, Organization::Addresses, Organization::EmailAddresses, Organization::PhoneNumbers, Page::Content, PartialInstitution, Participant::Photos, Participant::Policies, Participant::Rankings, Participant::Rankings::Ranking, Participant::Roles, Participant::Roles::Barber::License, Participant::Roles::Barber::Salon, Participant::Roles::Organizer::Policies, Participant::Roles::Organizer::PreviousOrganization, Participant::Roles::Role, Participant::ShaveSchedule, Participant::Totals, Payment::Details, Permissions, PermissionsAtEvent, Person::Addresses, Person::EmailAddresses, Person::HowAffected, Person::Occupation, Person::Occupation::EducationDetails, Person::Occupation::FinanceDetails, Person::Occupation::MilitaryDetails, Person::PhoneNumbers, Person::Policies, Phone, Photos, Search::Campaign, Search::Event, Search::Fund, Search::Fundraiser, Search::Kid, Search::Memorial, Search::Participant, Search::Team, ShaveSchedule::ShaveScheduleAssignment, ShaveSchedule::TimeSelectionPermissions, Summary::Totals, Team::Photos, Team::Rankings, Team::Rankings::Ranking, Team::Totals, ThirdPartyMedia, TopLevelEntity, TreatmentStatus, Venue, Venue::Social

Constant Summary collapse

ELSE =
->(_) { true }

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data = {}) ⇒ BaseEntity

Returns a new instance of BaseEntity.

Raises:



30
31
32
33
34
35
36
37
38
# File 'lib/stbaldricks/entities/lib/base.rb', line 30

def initialize(data = {})
  # If disallow instantiation has been set, raise an error if someone is trying to call initilaize
  raise SBF::Client::Error, 'Initialize is not valid on a base object. Use the full or partial version' unless self.class.allow_instantiation?

  super()

  @errors = ActiveModel::Errors.new(self)
  self.attributes = data
end

Instance Attribute Details

#errorsObject (readonly)

Returns the value of attribute errors.



19
20
21
# File 'lib/stbaldricks/entities/lib/base.rb', line 19

def errors
  @errors
end

Class Method Details

.allow_instantiation?Boolean

Class method which retrieves the

Returns:



209
210
211
# File 'lib/stbaldricks/entities/lib/base.rb', line 209

def self.allow_instantiation?
  !@disallow_instantiation
end

.attr_accessor(*vars) ⇒ Object



238
239
240
241
242
243
244
245
246
247
248
# File 'lib/stbaldricks/entities/lib/base.rb', line 238

def self.attr_accessor(*vars)
  attributes.merge(vars)
  super(*vars)

  vars.each do |attribute|
    define_attribute_methods attribute
    define_changing_attr_methods attribute, false, true
  end

  add_boolean_methods(vars, true)
end

.attr_reader(*vars) ⇒ Object

Override for the ruby built-in attribute accessors. Creates a list of attributes that can be accessed at will and adds some helper methods.



221
222
223
224
225
# File 'lib/stbaldricks/entities/lib/base.rb', line 221

def self.attr_reader(*vars)
  attributes.merge(vars)
  super(*vars)
  add_boolean_methods(vars)
end

.attr_writer(*vars) ⇒ Object



227
228
229
230
231
232
233
234
235
236
# File 'lib/stbaldricks/entities/lib/base.rb', line 227

def self.attr_writer(*vars)
  attributes.merge(vars)

  vars.each do |attribute|
    define_attribute_methods attribute
    define_changing_attr_methods attribute
  end

  add_boolean_methods(vars, true)
end

.attributesObject



341
342
343
# File 'lib/stbaldricks/entities/lib/base.rb', line 341

def self.attributes
  @attributes ||= Set.new
end

.collection_attributesObject



353
354
355
# File 'lib/stbaldricks/entities/lib/base.rb', line 353

def self.collection_attributes
  @collection_attributes ||= Set.new
end

.entity_attr_accessor(attribute, full_class, partial_class = nil, optional = false) ⇒ Object



290
291
292
293
# File 'lib/stbaldricks/entities/lib/base.rb', line 290

def self.entity_attr_accessor(attribute, full_class, partial_class = nil, optional = false)
  mapping_for_single_class = [[ELSE, full_class, partial_class]]
  multitype_attr_accessor(attribute, mapping_for_single_class, optional)
end

.entity_attr_reader(attribute, full_class, partial_class = nil, optional = false) ⇒ Object

Entity attr accessors are simpler to define/easier to read but they really just create a type mapping for the given inputs and then function the same as the multitype attribute accessors do.



280
281
282
283
# File 'lib/stbaldricks/entities/lib/base.rb', line 280

def self.entity_attr_reader(attribute, full_class, partial_class = nil, optional = false)
  mapping_for_single_class = [[ELSE, full_class, partial_class]]
  multitype_attr_reader(attribute, mapping_for_single_class, optional)
end

.entity_attr_writer(attribute, full_class, partial_class = nil, optional = false) ⇒ Object



285
286
287
288
# File 'lib/stbaldricks/entities/lib/base.rb', line 285

def self.entity_attr_writer(attribute, full_class, partial_class = nil, optional = false)
  mapping_for_single_class = [[ELSE, full_class, partial_class]]
  multitype_attr_writer(attribute, mapping_for_single_class, optional)
end

.entity_attributesObject



349
350
351
# File 'lib/stbaldricks/entities/lib/base.rb', line 349

def self.entity_attributes
  @entity_attributes ||= Set.new
end

.entity_collection_attr_accessor(attribute, full_class, partial_class = nil, optional = false) ⇒ Object



335
336
337
338
# File 'lib/stbaldricks/entities/lib/base.rb', line 335

def self.entity_collection_attr_accessor(attribute, full_class, partial_class = nil, optional = false)
  mapping_for_single_class = [[ELSE, full_class, partial_class]]
  multitype_collection_attr_accessor(attribute, mapping_for_single_class, optional)
end

.entity_collection_attr_reader(attribute, full_class, partial_class = nil, optional = false) ⇒ Object

Entity attr accessors are simpler to define/easier to read but they really just create a type mapping for the given inputs and then function the same as the multitype attribute accessors do.



325
326
327
328
# File 'lib/stbaldricks/entities/lib/base.rb', line 325

def self.entity_collection_attr_reader(attribute, full_class, partial_class = nil, optional = false)
  mapping_for_single_class = [[ELSE, full_class, partial_class]]
  multitype_collection_attr_reader(attribute, mapping_for_single_class, optional)
end

.entity_collection_attr_writer(attribute, full_class, partial_class = nil, optional = false) ⇒ Object



330
331
332
333
# File 'lib/stbaldricks/entities/lib/base.rb', line 330

def self.entity_collection_attr_writer(attribute, full_class, partial_class = nil, optional = false)
  mapping_for_single_class = [[ELSE, full_class, partial_class]]
  multitype_collection_attr_writer(attribute, mapping_for_single_class, optional)
end

.inherited(base) ⇒ Object



572
573
574
575
576
577
# File 'lib/stbaldricks/entities/lib/base.rb', line 572

def self.inherited(base)
  # Add all of our attributes to the class that is inheriting us.
  base.attributes.merge(attributes) unless attributes.empty?
  base.optional_attributes.merge(optional_attributes) unless optional_attributes.empty?
  base.entity_attributes.merge(entity_attributes) unless entity_attributes.empty?
end

.multitype_attr_accessor(attribute, class_mappings, optional = false) ⇒ Object



269
270
271
272
273
274
# File 'lib/stbaldricks/entities/lib/base.rb', line 269

def self.multitype_attr_accessor(attribute, class_mappings, optional = false)
  entity_attributes << attribute
  optional_attributes << attribute if optional
  attr_accessor(attribute)
  add_multitype_setter_method(attribute, class_mappings)
end

.multitype_attr_reader(attribute, class_mappings, optional = false) ⇒ Object

Multitype Attribute accessors. These methods take an array of type to class mappings. Expected form is:

[<lamda method which evals to true if this type should be used>, <full class>, <partial class>], […]


255
256
257
258
259
260
# File 'lib/stbaldricks/entities/lib/base.rb', line 255

def self.multitype_attr_reader(attribute, class_mappings, optional = false)
  entity_attributes << attribute
  optional_attributes << attribute if optional
  attr_reader(attribute)
  add_multitype_setter_method(attribute, class_mappings, true)
end

.multitype_attr_writer(attribute, class_mappings, optional = false) ⇒ Object



262
263
264
265
266
267
# File 'lib/stbaldricks/entities/lib/base.rb', line 262

def self.multitype_attr_writer(attribute, class_mappings, optional = false)
  entity_attributes << attribute
  optional_attributes << attribute if optional
  attr_writer(attribute)
  add_multitype_setter_method(attribute, class_mappings)
end

.multitype_collection_attr_accessor(attribute, class_mappings, optional = false) ⇒ Object



314
315
316
317
318
319
# File 'lib/stbaldricks/entities/lib/base.rb', line 314

def self.multitype_collection_attr_accessor(attribute, class_mappings, optional = false)
  collection_attributes << attribute
  optional_attributes << attribute if optional
  attr_accessor(attribute)
  add_multitype_collection_setter_method(attribute, class_mappings)
end

.multitype_collection_attr_reader(attribute, class_mappings, optional = false) ⇒ Object

Multitype Collection accessors. These methods take an array of type to class mappings. Expected form is:

[<lamda method which evals to true if this type should be used>, <full class>, <partial class>], […]


300
301
302
303
304
305
# File 'lib/stbaldricks/entities/lib/base.rb', line 300

def self.multitype_collection_attr_reader(attribute, class_mappings, optional = false)
  collection_attributes << attribute
  optional_attributes << attribute if optional
  attr_reader(attribute)
  add_multitype_collection_setter_method(attribute, class_mappings, true)
end

.multitype_collection_attr_writer(attribute, class_mappings, optional = false) ⇒ Object



307
308
309
310
311
312
# File 'lib/stbaldricks/entities/lib/base.rb', line 307

def self.multitype_collection_attr_writer(attribute, class_mappings, optional = false)
  collection_attributes << attribute
  optional_attributes << attribute if optional
  attr_writer(attribute)
  add_multitype_collection_setter_method(attribute, class_mappings)
end

.optional_attributesObject



345
346
347
# File 'lib/stbaldricks/entities/lib/base.rb', line 345

def self.optional_attributes
  @optional_attributes ||= Set.new
end

Instance Method Details

#add_errors(error) ⇒ Object



119
120
121
122
123
124
125
126
127
128
# File 'lib/stbaldricks/entities/lib/base.rb', line 119

def add_errors(error)
  errors.clear
  count = error.fields.length
  error.fields.each do |field|
    field = field.gsub('_id', '') # Hacky, since API returns DB field that errored instead of View Field
    errors.add(field, error.details) if count > 1
    errors.add(:base, "#{field}: #{error.details}") if count == 1
  end
  errors.add(:base, "#{error.type}: #{error.details}") if count == 0
end

#attributes=(data) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/stbaldricks/entities/lib/base.rb', line 100

def attributes=(data)
  data ||= {}
  data.each do |key, value|
    # Use the setter if one is available, otherwise set the variable directly
    setter = "#{key}=".to_sym
    if respond_to?(setter, true)
      send(setter, value)

    else
      instance_variable_set("@#{key}".to_sym, value)

    end
  end

  # For each attribute that may be optional, call mark_attribute_not_provided
  # if the data set does not contain a key with the optional attribute's name
  self.class.optional_attributes.each { |name| mark_attribute_not_provided(name) unless data.key?(name) }
end

#keys_dataObject



95
96
97
98
# File 'lib/stbaldricks/entities/lib/base.rb', line 95

def keys_data
  return {} unless respond_to?(:id)
  is_a?(SBF::Client::Event) ? {id: id, year: year} : {id: id}
end

#model_nameObject

Overridden from ActiveModel::Naming to remove namespace and Full/Partial



41
42
43
# File 'lib/stbaldricks/entities/lib/base.rb', line 41

def model_name
  @_model_name ||= ActiveModel::Name.new(self, SBF::Client, self.class.name.gsub(/::(Full|Partial)/, '::'))
end

#not_provided_attributesObject

Class method to retrieve the not_provided_attributes attribute



214
215
216
# File 'lib/stbaldricks/entities/lib/base.rb', line 214

def not_provided_attributes
  @not_provided_attributes ||= Set.new
end

#persisted?Boolean

Returns:



45
46
47
# File 'lib/stbaldricks/entities/lib/base.rb', line 45

def persisted?
  true
end

#reload!Object



49
50
51
52
# File 'lib/stbaldricks/entities/lib/base.rb', line 49

def reload!
  # get the values from the persistence layer
  clear_changes_information
end

#reload_recursiveObject



54
55
56
57
58
59
60
61
# File 'lib/stbaldricks/entities/lib/base.rb', line 54

def reload_recursive
  instance_variables.each do |var|
    attribute = instance_variable_get(var)
    attribute.reload_recursive if attribute.is_a?(BaseEntity)
    attribute.each { |a| a.reload_recursive if a.is_a?(BaseEntity) } if attribute.is_a?(Array)
  end
  reload!
end

#rollback!Object



63
64
65
# File 'lib/stbaldricks/entities/lib/base.rb', line 63

def rollback!
  restore_attributes
end

#to_hashObject

Recursively converts an entity into a Hash



529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
# File 'lib/stbaldricks/entities/lib/base.rb', line 529

def to_hash
  entity_hash = {}
  self.class.attributes.each { |key|
    # If the method was not retrieved, do not include it in the hash
    next if not_provided_attributes.include?(key)

    # Get the value
    value = send(key)

    # If the value is an Entity, call to_hash on it (recursively)
    if value.is_a?(BaseEntity)
      entity_hash[key] = value.to_hash

    # If the value is an Array, need to try to call to_hash on each item
    elsif value.is_a?(Array)
      entity_hash[key] = value.map { |element|
        if element.is_a?(BaseEntity)
          next element.to_hash
        else
          next element
        end
      }

    # Collections should return empty array rather than nil
    elsif value.nil? && self.class.collection_attributes.include?(key)
      entity_hash[key] = []

    # Just set the value
    else
      entity_hash[key] = value

    end
  }

  # Return the hash
  entity_hash
end

#to_json(*a) ⇒ Object

Recursively convert an entity into json



568
569
570
# File 'lib/stbaldricks/entities/lib/base.rb', line 568

def to_json(*a)
  to_hash.to_json(*a)
end

#update_data(with_keys = false) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/stbaldricks/entities/lib/base.rb', line 67

def update_data(with_keys = false)
  data = {}
  changes.each { |k, arr| data[k.to_sym] = arr[1] }

  instance_variables.each do |var|
    attribute = instance_variable_get(var)
    if attribute.is_a?(BaseEntity)
      if attribute.update_data.empty?
        data.delete(var.to_s.gsub('@', '').to_sym)
      else
        data.merge!(var.to_s.gsub('@', '').to_sym => attribute.update_data(true))
      end
    elsif attribute.is_a?(Array)
      selected = attribute.select { |a| a.is_a?(BaseEntity) || !attribute.update_data(true).empty? }
      attributes = selected.map { |s| s.update_data(true) }.reject(&:empty?)
      if attributes.empty?
        data.delete(var.to_s.gsub('@', '').to_sym)
      else
        data.merge!(var.to_s.gsub('@', '').to_sym => attributes)
      end
    end
  end

  return data if data.empty?

  with_keys ? keys_data.merge(data) : data
end