Class: SBF::Client::BaseEntity

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

Direct Known Subclasses

Address, AlternateShippingAddress, Api::Response, Campaign::Totals, Challenger::Totals, Diagnosis, Donation::EmployerMatched, 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, Event::Venue::Social, EventApplication::Requestor, FullOrganization::ContactName, Fund::Photos, Fund::Totals, Fund::YearlyTotals, Fundraiser::Photos, Fundraiser::Policies, Fundraiser::Rankings, Fundraiser::Rankings::Ranking, Fundraiser::Totals, FundraisingPage, GeoLocation, Grant::FullFundingType, Grant::FullResearcher, Grant::PartialFundingType, Grant::PartialResearcher, 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, Milestone, NamePiecesBase, NotImplementedObject, OptOutSettings, Organization::Addresses, Organization::EmailAddresses, Organization::PhoneNumbers, Organization::Totals, Page::Content, 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, Person::Totals, Phone, Photos, RecurringGift::Tribute, 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

Constant Summary collapse

ELSE =
->(_) { true }

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from EntityResponseConcern

#add_errors, #data, #error?, #errors?, #errors_http_code=, #http_code, #success?

Constructor Details

#initialize(data = {}, clear_changes = false) ⇒ BaseEntity

Returns a new instance of BaseEntity.

Raises:



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

def initialize(data = {}, clear_changes = false)
  # 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 = SBF::Client::Entity::Errors.new(self)
  initialize_attributes(data)
  reload_recursive if clear_changes
end

Instance Attribute Details

#errorsObject (readonly)

Returns the value of attribute errors.



17
18
19
# File 'lib/stbaldricks/entities/lib/base.rb', line 17

def errors
  @errors
end

Class Method Details

.allow_instantiation?Boolean

Class method which retrieves the

Returns:



218
219
220
# File 'lib/stbaldricks/entities/lib/base.rb', line 218

def self.allow_instantiation?
  !@disallow_instantiation
end

.attr_accessor(*vars) ⇒ Object



247
248
249
250
251
252
253
254
255
256
257
# File 'lib/stbaldricks/entities/lib/base.rb', line 247

def self.attr_accessor(*vars)
  defined_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.



230
231
232
233
234
# File 'lib/stbaldricks/entities/lib/base.rb', line 230

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

.attr_writer(*vars) ⇒ Object



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

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

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

  add_boolean_methods(vars, true)
end

.collection_attributesObject



362
363
364
# File 'lib/stbaldricks/entities/lib/base.rb', line 362

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

.defined_attributesObject



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

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

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



299
300
301
302
# File 'lib/stbaldricks/entities/lib/base.rb', line 299

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.



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

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



294
295
296
297
# File 'lib/stbaldricks/entities/lib/base.rb', line 294

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



358
359
360
# File 'lib/stbaldricks/entities/lib/base.rb', line 358

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

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



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

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.



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

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



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

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



585
586
587
588
589
590
# File 'lib/stbaldricks/entities/lib/base.rb', line 585

def self.inherited(base)
  # Add all of our attributes to the class that is inheriting us.
  base.defined_attributes.merge(defined_attributes) unless defined_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



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

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>], […]


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

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



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

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



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

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>], […]


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

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



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

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



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

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

Instance Method Details

#destroyed?Boolean

Returns:



66
67
68
# File 'lib/stbaldricks/entities/lib/base.rb', line 66

def destroyed?
  @destroyed
end

#dirty_data(with_keys = false) ⇒ Hash

Returns a hash of changed data for the entity and its sub-entities

Parameters:

  • with_keys (Boolean) (defaults to: false)

    when true, include the keys of the current entity. (sub-entity keys will always be included if they are present)

Returns:

  • (Hash)

    the changed data



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/stbaldricks/entities/lib/base.rb', line 79

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

  instance_variables.each do |var|
    attribute_symbol = var.to_s.delete('@').to_sym
    attribute = instance_variable_get(var)
    if attribute.is_a?(BaseEntity)
      if attribute.dirty_data(true).empty?
        next unless changed.map(&:to_sym).include?(attribute_symbol)

        data.merge!(attribute_symbol => attribute.keys_hash)
      else
        data.merge!(attribute_symbol => attribute.dirty_data(true))
      end
    elsif attribute.is_a?(Array)
      next unless attribute.all? { |e| e.is_a?(BaseEntity) } && attribute.any? { |e| !e.dirty_data(true).empty? }

      data.merge!(attribute_symbol => attribute)
    end
  end

  return data if data.empty?

  with_keys ? keys_hash.merge(data) : data
end

#errorObject

Attempt to return an ErrorEntity similar to or exactly like the original



595
596
597
598
599
600
601
602
603
604
605
606
607
608
# File 'lib/stbaldricks/entities/lib/base.rb', line 595

def error
  log_deprecated('error', caller)
  return nil if single_active_model_error.nil?

  details = single_active_model_error.find { |x| x.is_a?(String) } if single_active_model_error.is_a?(Array)
  details ||= single_active_model_error.is_a?(String) ? single_active_model_error : nil
  field = single_active_model_error.is_a?(Array) ? single_active_model_error.find { |x| x.is_a?(Symbol) && x != :base } : nil

  fields = errors.keys.reject { |k| k == :base }.empty? ? nil : errors.keys.reject { |k| k == :base }.map(&:to_s)
  details = details["#{errors.type}: ".length..(details.length - 1)] if details.start_with?("#{errors.type}: ")
  details = details["#{field}: ".length..(details.length - 1)] if details.start_with?("#{field}: ")

  SBF::Client::ErrorEntity.new(code: errors.code, type: errors.type, details: details, errors: fields)
end

#keys_hashObject



106
107
108
# File 'lib/stbaldricks/entities/lib/base.rb', line 106

def keys_hash
  respond_to?(:id) && id ? {id: id} : {}
end

#model_nameObject

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



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

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



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

def not_provided_attributes
  @not_provided_attributes ||= Set.new
end

#persisted?Boolean

Returns:



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

def persisted?
  true
end

#reload!Object



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

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

#reload_recursiveObject



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

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



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

def rollback!
  restore_attributes
end

#to_hashObject

Recursively converts an entity into a Hash



544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
# File 'lib/stbaldricks/entities/lib/base.rb', line 544

def to_hash
  entity_hash = {}
  self.class.defined_attributes.each do |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)
    entity_hash[key] = if value.is_a?(BaseEntity)
                         value.to_hash

                       # If the value is an Array, need to try to call to_hash on each item
                       elsif value.is_a?(Array)
                         value.map do |element|
                           next element.to_hash if element.is_a?(BaseEntity)

                           next element
                         end

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

                       # Just set the value
                       else
                         value

                       end
  end

  # Return the hash
  entity_hash
end

#to_json(*a) ⇒ Object

Recursively convert an entity into json



581
582
583
# File 'lib/stbaldricks/entities/lib/base.rb', line 581

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

#to_partialObject



70
71
72
73
74
# File 'lib/stbaldricks/entities/lib/base.rb', line 70

def to_partial
  base_class = self.class.name.gsub(/(.*::)(Full|Partial)(.*)/, '\1')
  base_name = self.class.name.gsub(/(.*::)(Full|Partial)(.*)/, '\3')
  "#{base_class}Partial#{base_name}".to_class.new(to_hash)
end