Class: Lockstep::ApiRecord

Inherits:
Object
  • Object
show all
Extended by:
ActiveModel::Callbacks, ActiveModel::Naming
Includes:
ActiveModel::AttributeMethods, ActiveModel::Conversion, ActiveModel::Validations, ActiveModel::Validations::Callbacks, Lockstep::ApiRecords::Scopes, QueryMethods
Defined in:
app/concepts/lockstep/api_record.rb

Direct Known Subclasses

Account, AccountingProfile, ApiKey, AppEnrollment, Attachment, CompanyMagicLinkSummary, Connection, Contact, CustomFieldValue, CustomerSummary, FeatureFlag, FinancialInstitutionAccount, Invoice, InvoiceAtRiskSummary, InvoiceSummary, Invoices::Address, MagicLink, MagicLinkSummary, Note, Payment, PaymentApplied, PaymentSummary, ReportApAgingHeader, ReportArAgingHeader, ReportCashflow, ReportDailyPayableOutstanding, ReportDailyPayableOutstandingSummary, ReportDailySalesOutstanding, ReportPayableComingDue, ReportPayableComingDueSummary, ReportPayableSummary, ReportRiskRate, ServiceFabricPayment, SyncRequest, Transaction, TranscriptionValidationRequest, User, VendorSummary, Webhook, WorkflowStatus, Schema::AccountAuthorisation, Schema::AccountingProfile, Schema::AccountingProfileContact, Schema::AccountingProfileContactFetchResult, Schema::AccountingProfileContactResult, Schema::AccountingProfileContactResultFetchResult, Schema::AccountingProfileFetchResult, Schema::AccountingProfileRequest, Schema::ActionResult, Schema::Activity, Schema::ActivityFetchResult, Schema::ActivityStreamItem, Schema::ActivityXRef, Schema::Address, Schema::Aging, Schema::AgingBucketResult, Schema::Amount, Schema::ApAgingHeaderInfo, Schema::ApHeaderInfo, Schema::ApiKey, Schema::ApiKeyFetchResult, Schema::AppEnrollment, Schema::AppEnrollmentCustomField, Schema::AppEnrollmentCustomFieldFetchResult, Schema::AppEnrollmentFetchResult, Schema::AppEnrollmentReconnectInfo, Schema::Application, Schema::ApplicationFetchResult, Schema::ArAgingHeaderInfo, Schema::ArHeaderInfo, Schema::Assembly, Schema::AtRiskInvoiceSummary, Schema::AtRiskInvoiceSummaryFetchResult, Schema::Attachment, Schema::AttachmentErpUpdate, Schema::AttachmentFetchResult, Schema::AttachmentHeaderInfo, Schema::AttachmentLink, Schema::AttachmentLinkFetchResult, Schema::BaseCurrencySync, Schema::BatchSync, Schema::BulkCurrencyConversion, Schema::BulkDeleteRequest, Schema::CashflowReport, Schema::CodeDefinition, Schema::CodeDefinitionFetchResult, Schema::Company, Schema::CompanyDetails, Schema::CompanyDetailsPayment, Schema::CompanyFetchResult, Schema::CompanyIdentifier, Schema::CompanyMagicLinkSummary, Schema::CompanyMagicLinkSummaryFetchResult, Schema::CompanySync, Schema::ConnectorInfo, Schema::ConstructorInfo, Schema::Contact, Schema::ContactFetchResult, Schema::ContactSync, Schema::Country, Schema::CountryFetchResult, Schema::CreditMemoApplied, Schema::CreditMemoAppliedFetchResult, Schema::CreditMemoAppliedSync, Schema::CreditMemoInvoice, Schema::CreditorAccount, Schema::Currency, Schema::CurrencyFetchResult, Schema::CurrencyRate, Schema::CustomAttributeData, Schema::CustomAttributeNamedArgument, Schema::CustomAttributeTypedArgument, Schema::CustomFieldDefinition, Schema::CustomFieldDefinitionFetchResult, Schema::CustomFieldSync, Schema::CustomFieldValue, Schema::CustomFieldValueFetchResult, Schema::CustomerDetails, Schema::CustomerDetailsPayment, Schema::CustomerSummary, Schema::CustomerSummaryFetchResult, Schema::DailyPayableOutstandingReport, Schema::DailyPayableOutstandingSummaryReport, Schema::DailySalesOutstandingReport, Schema::DebtorAccount, Schema::DebtorAgentAccount, Schema::DeleteResult, Schema::DeveloperAccountSubmit, Schema::DirectoryCompany, Schema::DpoSummary, Schema::DpoSummaryFetchResult, Schema::DpoSummaryGroupTotal, Schema::EInvoiceAttachment, Schema::Email, Schema::EmailFetchResult, Schema::EmailReplyGeneratorRequest, Schema::EmailReplyGeneratorResponse, Schema::EmailReplyGeneratorSuggestions, Schema::Erp, Schema::ErpFetchResult, Schema::ErpInfo, Schema::ErpInfoData, Schema::Error, Schema::EventInfo, Schema::Exception, Schema::ExternalConnector, Schema::ExternalConnectorAuth, Schema::ExternalConnectorAuthRequest, Schema::ExternalConnectorToken, Schema::FeatureFlag, Schema::FeatureFlagsRequest, Schema::FeatureFlagsResponse, Schema::FieldInfo, Schema::FinancialAccount, Schema::FinancialAccountBalanceHistory, Schema::FinancialAccountBalanceHistoryFetchResult, Schema::FinancialAccountBalanceHistorySync, Schema::FinancialAccountFetchResult, Schema::FinancialAccountSync, Schema::FinancialInstitutionAccount, Schema::FinancialInstitutionAccountFetchResult, Schema::FinancialReport, Schema::FinancialReportCell, Schema::FinancialReportRow, Schema::FinancialYearSetting, Schema::FinancialYearSettingFetchResult, Schema::FinancialYearSettingSync, Schema::GroupAccount, Schema::InboundCompanySync, Schema::InboundInvoiceSync, Schema::InboundPaymentApplication, Schema::InboundPaymentSync, Schema::InboundSyncInvoiceLines, Schema::InboundSyncPrimaryContact, Schema::InboundSyncReportData, Schema::InboundSyncReportDataJsonApiData, Schema::InboundSyncReportSummary, Schema::InsertPaymentAppliedRequest, Schema::InsertPaymentRequest, Schema::InsertPaymentRequestErpWriteSyncSubmit, Schema::InstructedAmount, Schema::Invite, Schema::InviteData, Schema::InviteSubmit, Schema::Invoice, Schema::InvoiceAddress, Schema::InvoiceAddressFetchResult, Schema::InvoiceAtRiskSummary, Schema::InvoiceFetchResult, Schema::InvoiceHistory, Schema::InvoiceHistoryFetchResult, Schema::InvoiceLine, Schema::InvoiceLineFetchResult, Schema::InvoiceLineSync, Schema::InvoicePaymentDetail, Schema::InvoiceSummary, Schema::InvoiceSummaryFetchResult, Schema::InvoiceSummaryInvoiceSummaryTotalsSummaryFetchResult, Schema::InvoiceSummaryTotals, Schema::InvoiceSync, Schema::InvoiceWorkflowStatusHistory, Schema::InvoiceWorkflowStatusSync, Schema::JournalEntry, Schema::JournalEntryFetchResult, Schema::JournalEntryLine, Schema::JournalEntryLineFetchResult, Schema::JournalEntryLineSync, Schema::JournalEntrySync, Schema::JsonApiResourceHead, Schema::Lead, Schema::MagicLink, Schema::MagicLinkFetchResult, Schema::MagicLinkStatus, Schema::MagicLinkSummary, Schema::ManifestResponse, Schema::MemberInfo, Schema::Meta, Schema::Metadata, Schema::MethodBase, Schema::MethodInfo, Schema::Module, Schema::ModuleHandle, Schema::Note, Schema::NoteFetchResult, Schema::NotificationData, Schema::ParameterInfo, Schema::PayableComingDueReport, Schema::PayableComingDueSummaryReport, Schema::PayableSummaryReport, Schema::PayablesComingDue, Schema::PayablesComingDueFetchResult, Schema::PayablesComingDueHeader, Schema::PayablesComingDueWidget, Schema::PayablesSummaryReport, Schema::Payment, Schema::PaymentApplied, Schema::PaymentAppliedFetchResult, Schema::PaymentAppliedSync, Schema::PaymentDetail, Schema::PaymentDetailFetchResult, Schema::PaymentDetailHeader, Schema::PaymentErpWriteResult, Schema::PaymentFetchResult, Schema::PaymentInstrument, Schema::PaymentResponse, Schema::PaymentSummary, Schema::PaymentSummaryFetchResult, Schema::PaymentSummaryPaymentSummaryTotalsSummaryFetchResult, Schema::PaymentSummaryTotals, Schema::PaymentSync, Schema::ProblemDetails, Schema::PropertyInfo, Schema::Provisioning, Schema::ProvisioningFinalizeRequest, Schema::ProvisioningResponse, Schema::PublicCompanyProfile, Schema::PublicCompanyProfileFetchResult, Schema::Relationship, Schema::RelationshipDetail, Schema::RemittanceInformation, Schema::ReportingAmount, Schema::RiskInformation, Schema::RiskRate, Schema::RuntimeFieldHandle, Schema::RuntimeMethodHandle, Schema::RuntimeTypeHandle, Schema::SettlementDiscount, Schema::SettlementDiscountsInfo, Schema::SfAccountResponse, Schema::SfCompanyRequest, Schema::SfCompanyResponse, Schema::SfCustomerRequest, Schema::SfCustomerResponse, Schema::SfEnrollRequest, Schema::SfEnrollResponse, Schema::SfNotification, Schema::SfOrganisationRequest, Schema::SfOrganisationResponse, Schema::SfPaymentQueryResponse, Schema::SfPaymentRequest, Schema::SfPaymentResponse, Schema::SfServicerResponse, Schema::SfServicersAuthRequest, Schema::SfServicersAuthResponse, Schema::SfSubmitPaymentInfo, Schema::Source, Schema::State, Schema::StateFetchResult, Schema::Status, Schema::StructLayoutAttribute, Schema::SummaryAgingTotals, Schema::SupportAccess, Schema::SupportAccessRequest, Schema::SyncEntityResult, Schema::SyncPayload, Schema::SyncRequest, Schema::SyncRequestFetchResult, Schema::SyncSubmit, Schema::TaxSummary, Schema::TestArgumentException, Schema::TestTimeoutException, Schema::Transaction, Schema::TransactionCurrencySummary, Schema::TransactionDetail, Schema::TransactionSummaryTotal, Schema::TransactionTransactionSummaryTotalSummaryFetchResult, Schema::TranscriptionRequestSubmit, Schema::TranscriptionValidationRequest, Schema::TranscriptionValidationRequestFetchResult, Schema::TranscriptionValidationRequestItem, Schema::TranscriptionValidationRequestItemFetchResult, Schema::TransferOwner, Schema::TransferOwnerSubmit, Schema::Type, Schema::TypeInfo, Schema::Uri, Schema::UserAccount, Schema::UserAccountFetchResult, Schema::UserDataResponse, Schema::UserGroup, Schema::UserRole, Schema::UserRoleFetchResult, Schema::VendorSummary, Schema::VendorSummaryFetchResult, Schema::ViewBoxSettings, Schema::Webhook, Schema::WebhookFetchResult, Schema::WebhookHistoryTableStorage, Schema::WebhookHistoryTableStorageFetchResult, Schema::WebhookRule, Schema::WebhookRuleFetchResult, Schema::WorkflowStatus, Schema::WorkflowStatusFetchResult

Defined Under Namespace

Modules: ClassMethods

Constant Summary collapse

HashWithIndifferentAccess =
ActiveSupport::HashWithIndifferentAccess

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attributes = {}, new = true) ⇒ Lockstep::ApiRecord

Instantiates a Lockstep::ApiRecord object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'app/concepts/lockstep/api_record.rb', line 45

def initialize(attributes = {}, new = true)
  # attributes = HashWithIndifferentAccess.new(attributes)

  if new
    @unsaved_attributes = attributes
    @unsaved_attributes.stringify_keys!
  else
    @unsaved_attributes = {}
  end
  @attributes = {}
  self.error_instances = []

  attributes.each do |k, v|
    # Typecast using dry-types
    if (type = schema[k])
      attributes[k] = type[v]
    elsif v.present? and (enum = enum_config[k]).present? and enum.keys.include?(v.to_s)
      attributes[k] = enum[v]
    end
  end

  self.attributes.merge!(attributes)
  self.attributes unless self.attributes.empty?
  create_setters_and_getters!
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *_args) ⇒ Object

Raises:

  • (StandardError)


219
220
221
222
# File 'app/concepts/lockstep/api_record.rb', line 219

def method_missing(method, *_args)
  raise StandardError, "#{method} has not been defined for #{self.class.name}"
  # super
end

Class Attribute Details

.id_refObject

Raises:

  • (StandardError)


293
294
295
296
297
# File 'app/concepts/lockstep/api_record.rb', line 293

def self.id_ref
  raise StandardError, "id_ref has not been defined for #{name}" if @id_ref.blank?

  @id_ref
end

.model_name_uriObject

Returns the value of attribute model_name_uri.



315
316
317
# File 'app/concepts/lockstep/api_record.rb', line 315

def model_name_uri
  @model_name_uri
end

.query_pathObject



359
360
361
# File 'app/concepts/lockstep/api_record.rb', line 359

def self.query_path
  @query_path || 'query'
end

Instance Attribute Details

#error_instancesObject

Returns the value of attribute error_instances.



35
36
37
# File 'app/concepts/lockstep/api_record.rb', line 35

def error_instances
  @error_instances
end

Class Method Details

.additional_query_params(args) ⇒ Object



550
551
552
# File 'app/concepts/lockstep/api_record.rb', line 550

def self.additional_query_params(args)
  query_builder.additional_query_params(args)
end

.alias_attribute(new_name, old_name) ⇒ Object

Enum implementation - End



1142
1143
1144
1145
1146
1147
1148
1149
1150
# File 'app/concepts/lockstep/api_record.rb', line 1142

def self.alias_attribute(new_name, old_name)
  define_method(new_name) do
    send(old_name)
  end

  define_method("#{new_name}=") do |value|
    send("#{old_name}=", value)
  end
end

.belongs_to(parent, config = {}) ⇒ Object

Similar to its ActiveRecord counterpart.

Parameters:

  • options (Hash)

    Added so that you can specify :class_name => ‘…’. It does nothing at all, but helps you write self-documenting code.



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'app/concepts/lockstep/api_record.rb', line 126

def self.belongs_to(parent, config = {})
  config = config.with_indifferent_access
  class_name = config[:class_name]
  raise "Class name cannot be empty in #{parent}: #{name}" if class_name.blank?

  included = config[:included] || false
  primary_key = config[:primary_key]
  foreign_key = config[:foreign_key]
  polymorphic = config[:polymorphic]
  loader = config[:loader]

  primary_key ||= class_name.constantize.id_ref
  foreign_key ||= class_name.constantize.id_ref
  field(parent)
  belongs_to_relations[parent] = {
    name: parent, class_name: class_name,
    included: included, primary_key: primary_key, foreign_key: foreign_key,
    loader: loader, polymorphic: polymorphic
  }

  # define_method("build_#{parent}") do |attributes_hash|
  #   build_belongs_to_association(parent, attributes_hash)
  # end
end

.belongs_to_relationsObject



950
951
952
# File 'app/concepts/lockstep/api_record.rb', line 950

def self.belongs_to_relations
  @belongs_to_relations ||= {}.with_indifferent_access
end

.bulk_import(new_objects, slice_size = nil) ⇒ Object

def self.delete_all(o)

raise StandardError.new("delete_all doesn't exist. Did you mean destroy_all?")

end



426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
# File 'app/concepts/lockstep/api_record.rb', line 426

def self.bulk_import(new_objects, slice_size = nil)
  return [] if new_objects.blank?

  # default slice size to 1000, if its blank or if its 0
  slice_size = 1000 if slice_size.blank? || slice_size.to_i == 0

  # Batch saves seem to fail if they're too big. We'll slice it up into multiple posts if they are.
  new_objects.each_slice(slice_size) do |objects|
    # attributes_for_saving
    batch_json = []

    objects.each do |item|
      unless item.new?
        raise StandardError,
              'Bulk Import cannot only create records at the moment. It cannot update records'
      end

      batch_json << item.attributes_for_saving.transform_keys { |key| key.camelize(:lower) }
    end

    resp = resource.post('', body: batch_json)
    # TODO: attach errors if resp code is 400
    if resp.code != '200'
      # Error format in JSON
      #   "errors": {
      #     "[0].EmailAddress": [
      #       "The EmailAddress field is not a valid e-mail address."
      #     ]
      #   }
      if resp.code == '401'
        raise Lockstep::Exceptions::UnauthorizedError, 'Unauthorized: Check your App ID & Master Key'
      elsif resp.code == '400'
        raise Lockstep::Exceptions::BadRequestError, JSON.parse(resp.body)
      elsif resp.code == '404'
        raise Lockstep::Exceptions::RecordNotFound, 'Resource not found in the Platfrom'
      end
    end

    response = JSON.parse(resp.body)
    next unless response && response.is_a?(Array) && response.length == objects.length

    # return response.map { |item|
    #   Lockstep::Contact.new(item.transform_keys { |key| key.underscore }, false)
    # }
    merge_all_attributes(objects, response)
  end
  new_objects
end

.chunk(attribute) ⇒ Object



560
561
562
# File 'app/concepts/lockstep/api_record.rb', line 560

def self.chunk(attribute)
  query_builder.chunk(attribute)
end

.class_attributesObject



575
576
577
# File 'app/concepts/lockstep/api_record.rb', line 575

def self.class_attributes
  @class_attributes ||= {}
end

.configObject



318
319
320
# File 'app/concepts/lockstep/api_record.rb', line 318

def self.config
  @config ||= Rails.application.config_for(:lockstep_client)
end

.create(attributes = {}) ⇒ Lockstep::ApiRecord

Create a Lockstep::ApiRecord object.

Parameters:

  • attributes (Hash) (defaults to: {})

    a ‘Hash` of attributes

Returns:

  • (Lockstep::ApiRecord)

    an object that subclasses ‘Lockstep::ApiRecord`. Or returns `false` if object fails to save.



568
569
570
571
572
573
# File 'app/concepts/lockstep/api_record.rb', line 568

def self.create(attributes = {})
  attributes = HashWithIndifferentAccess.new(attributes)
  obj = new(attributes)
  obj.save
  obj
end

.destroy_all(id: []) ⇒ Object



818
819
820
821
822
823
824
825
826
827
828
# File 'app/concepts/lockstep/api_record.rb', line 818

def self.destroy_all(id: [])
  id.each_slice(100) do |sliced_ids|
    resp = resource.delete('', body: { 'idsToDelete' => sliced_ids })
    return false unless resp.code.to_s == '200'
    # TODO: Since this could fail for certain IDs return deleted_ids in batch
  end
  
  @attributes = {}
  @unsaved_attributes = {}
  return true
end

.enum(config) ⇒ Object



1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
# File 'app/concepts/lockstep/api_record.rb', line 1084

def self.enum(config)
  config.each do |attribute, values|
    # Standardise values to hash
    if values.is_a?(Array)
      value_map = {}.with_indifferent_access
      values.each { |item| value_map[item] = item }
    elsif values.is_a?(Hash)
      value_map = values.with_indifferent_access
    else
      raise StandardError, "Invalid values for enum #{attribute}"
    end

    # Convert values to string if the value is symbol
    value_map.each { |k, v| value_map[k] = v.to_s if v.is_a?(Symbol) }

    enum_config[attribute] = value_map
    class_eval do
      value_map.each do |k, v|
        define_method("#{k}!") do
          set_attribute(attribute, v)
          return save if persisted?

          true
        end

        define_method("#{k}?") do
          get_attribute(attribute) == v
        end
      end
    end
  end
end

.enum_configObject

Enum implementation - Start



1076
1077
1078
# File 'app/concepts/lockstep/api_record.rb', line 1076

def self.enum_config
  @enum_config ||= {}.with_indifferent_access
end

.executeObject



554
555
556
# File 'app/concepts/lockstep/api_record.rb', line 554

def self.execute
  query_builder.execute
end

.field(fname, type = nil) ⇒ Object

Explicitly adds a field to the model.

Parameters:

  • name (Symbol)

    the name of the field, eg ‘:author`.

  • val (Boolean)

    the return value of the field. Only use this within the class.



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'app/concepts/lockstep/api_record.rb', line 83

def self.field(fname, type = nil)
  schema[fname] = type

  fname = fname.to_sym
  class_eval do
    define_method(fname) do
      val = get_attribute(fname.to_s)

      # If enum, substitute with the enum key
      if val.present? && (enum = enum_config[fname]).present?
        val = enum.key(val)
      end

      val
    end
  end
  unless respond_to? "#{fname}="
    class_eval do
      define_method("#{fname}=") do |val|
        set_attribute(fname.to_s, val)

        val
      end
    end
  end
end

.fields(*args) ⇒ Object

Add multiple fields in one line. Same as ‘#field`, but accepts multiple args.

Parameters:

  • *args (Array)

    an array of ‘Symbol`s, `eg :author, :body, :title`.



113
114
115
# File 'app/concepts/lockstep/api_record.rb', line 113

def self.fields(*args)
  args.each { |f| field(f) }
end

.find(id) ⇒ Lockstep::ApiRecord

Find a Lockstep::ApiRecord object by ID

Parameters:

  • id (String)

    the ID of the Parse object you want to find.

Returns:

Raises:



522
523
524
525
526
527
528
529
# File 'app/concepts/lockstep/api_record.rb', line 522

def self.find(id)
  raise Lockstep::Exceptions::RecordNotFound, "Couldn't find #{name} without an ID" if id.blank?

  record = where(id_ref => id).first
  raise Lockstep::Exceptions::RecordNotFound, "Couldn't find #{name} with id: #{id}" if record.blank?

  record
end

.find_by(*args) ⇒ Object

Find a Lockstep::ApiRecord object by given key/value pair



533
534
535
536
537
538
539
540
541
542
# File 'app/concepts/lockstep/api_record.rb', line 533

def self.find_by(*args)
  raise Lockstep::Exceptions::RecordNotFound, "Couldn't find an object without arguments" if args.blank?

  key, value = args.first.first
  unless valid_attribute?(key, raise_exception: true)
    raise StandardError, "Attribute '#{key}' has not been defined for #{name}"
  end

  where(key => value).first
end

.has_many(parent, config = {}) ⇒ Object

Creates setter and getter in order access the specified relation for this Model

Parameters:

  • options (Hash)

    Added so that you can specify :class_name => ‘…’. It does nothing at all, but helps you write self-documenting code.



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'app/concepts/lockstep/api_record.rb', line 157

def self.has_many(parent, config = {})
  config = config.with_indifferent_access
  class_name = config[:class_name]
  raise "Class name cannot be empty in #{parent}: #{name}" if class_name.blank?

  included = config[:included] || false
  primary_key = config[:primary_key]
  foreign_key = config[:foreign_key]
  polymorphic = config[:polymorphic]
  loader = config[:loader]

  primary_key ||= id_ref
  foreign_key ||= id_ref
  field(parent)
  has_many_relations[parent] = {
    name: parent, class_name: class_name, included: included,
    primary_key: primary_key, foreign_key: foreign_key, polymorphic: polymorphic,
    loader: loader
  }
end

.has_many_relationsObject



937
938
939
# File 'app/concepts/lockstep/api_record.rb', line 937

def self.has_many_relations
  @has_many_relations ||= {}.with_indifferent_access
end

.included(base) ⇒ Object



988
989
990
# File 'app/concepts/lockstep/api_record.rb', line 988

def self.included(base)
  base.extend(ClassMethods)
end

.load_schema(schema) ⇒ Object



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'app/concepts/lockstep/api_record.rb', line 178

def self.load_schema(schema)
  schema.schema.each do |field, type|
    field(field, type)
  end

  schema.belongs_to_relations.each do |relation, config|
    params = {}
    config.except(:name).each { |k, v| params[k.to_sym] = v }
    belongs_to(relation, params)
  end

  schema.has_many_relations.each do |relation, config|
    params = {}
    config.except(:name).each { |k, v| params[k.to_sym] = v }
    has_many(relation, params)
  end
end

.lockstep_belongs_to_relationsObject

Alias for belongs_to_relations



959
960
961
# File 'app/concepts/lockstep/api_record.rb', line 959

def self.lockstep_belongs_to_relations
  belongs_to_relations
end

.lockstep_has_many_relationsObject

Alias for has_many_relations



946
947
948
# File 'app/concepts/lockstep/api_record.rb', line 946

def self.lockstep_has_many_relations
  has_many_relations
end

.merge_all_attributes(objects, response) ⇒ Object

Batch requests Sends multiple requests to /batch Set slice_size to send larger batches. Defaults to 20 to prevent timeouts. Parse doesn’t support batches of over 20.

def self.batch_save(save_objects, slice_size = 20, method = nil)

return true if save_objects.blank?

res = self.resource

# Batch saves seem to fail if they're too big. We'll slice it up into multiple posts if they are.
save_objects.each_slice(slice_size) do |objects|
  # attributes_for_saving
  batch_json = { "requests" => [] }

  objects.each do |item|
    method ||= (item.new?) ? "POST" : "PATCH"
    object_path = "/1/#{item.class.model_name_uri}"
    object_path = "#{object_path}/#{item.id}" if item.id
    json = {
      "method" => method,
      "path" => object_path
    }
    json["body"] = item.attributes_for_saving unless method == "DELETE"
    batch_json["requests"] << json
  end
  res.post(batch_json.to_json, :content_type => "application/json") do |resp, req, res, &block|
    response = JSON.parse(resp) rescue nil
    if resp.code == 400
      return false
    end
    if response && response.is_a?(Array) && response.length == objects.length
      merge_all_attributes(objects, response) unless method == "DELETE"
    end
  end
end
true

end



402
403
404
405
406
407
408
409
410
411
# File 'app/concepts/lockstep/api_record.rb', line 402

def self.merge_all_attributes(objects, response)
  objects.each_with_index do |item, index|
    next unless response[index]

    new_attributes = response[index].transform_keys { |key| key.underscore }
    item.merge_attributes(new_attributes)
  end

  true
end

.method_missing(method_name, *args) ⇒ Object



224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'app/concepts/lockstep/api_record.rb', line 224

def self.method_missing(method_name, *args)
  method_name = method_name.to_s
  if method_name.start_with?('find_by_')
    attrib = method_name.gsub(/^find_by_/, '')
    finder_name = "find_all_by_#{attrib}"

    define_singleton_method(finder_name) do |target_value|
      where({ attrib.to_sym => target_value }).first
    end

    send(finder_name, args[0])
  elsif method_name.start_with?('find_all_by_')
    attrib = method_name.gsub(/^find_all_by_/, '')
    finder_name = "find_all_by_#{attrib}"

    define_singleton_method(finder_name) do |target_value|
      where({ attrib.to_sym => target_value }).all
    end

    send(finder_name, args[0])
  else
    super(method_name.to_sym, *args)
  end
end

.model_base_uriObject

Gets the current class’s Lockstep.io base_uri

Raises:

  • (StandardError)


323
324
325
326
327
328
329
330
331
332
333
334
335
# File 'app/concepts/lockstep/api_record.rb', line 323

def self.model_base_uri
  if name.starts_with?('Schema::')
    raise StandardError,
          'Cannot establish connection for auto-generated Schema. Create a new model if you want to retrieve data from Lockstep Platform'
  end
  raise StandardError, "URL Path is not defined for #{name}" if model_name_uri.blank?

  base_url = config[:base_url]
  base_url += '/' unless base_url.ends_with?('/')
  base_url += model_name_uri
  base_url += '/' unless base_url.ends_with?('/')
  base_url
end

.primary_keyObject

Alias for id_ref. Used by polymorphic association



300
301
302
# File 'app/concepts/lockstep/api_record.rb', line 300

def self.primary_key
  id_ref
end

.resourceObject

Creates a RESTful resource sends requests to [base_uri]/



345
346
347
348
349
350
351
352
353
# File 'app/concepts/lockstep/api_record.rb', line 345

def self.resource
  # load_settings

  # refactor to settings['app_id'] etc
  # app_id     = @@settings['app_id']
  # master_key = @@settings['master_key']
  # RestClient::Resource.new(self.model_base_uri, app_id, master_key)
  Lockstep::Client.new(model_base_uri)
end

.schemaObject



71
72
73
# File 'app/concepts/lockstep/api_record.rb', line 71

def self.schema
  @schema ||= {}.with_indifferent_access
end

.single_record!Object



1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
# File 'app/concepts/lockstep/api_record.rb', line 1126

def self.single_record!
  define_singleton_method :record do
    resp = resource.get('')

    return [] if %w(404).include?(resp.code.to_s)
    # TODO handle non 200 response code. Throwing an exception for now
    raise StandardError.new("#{resp.code} error while fetching: #{resp.body}") unless %w(201 200).include?(resp.code.to_s)

    result = JSON.parse(resp.body)
    r = result.transform_keys { |key| key.underscore }
    model_name.to_s.constantize.new(r, false)
  end
end

.to_date_object(date) ⇒ Object



201
202
203
204
205
206
# File 'app/concepts/lockstep/api_record.rb', line 201

def self.to_date_object(date)
  date = date.to_time if date.respond_to?(:to_time)
  if date && (date.is_a?(Date) || date.is_a?(DateTime) || date.is_a?(Time))
   date.getutc.iso8601(fraction_digits = 3)
  end
end

.valid_attribute?(key, raise_exception: false) ⇒ Boolean

Returns:

  • (Boolean)

Raises:

  • (StandardError)


579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
# File 'app/concepts/lockstep/api_record.rb', line 579

def self.valid_attribute?(key, raise_exception: false)
  # Valid only if the record is not an API record.
  # Default scopes build queries using ApiRecord to avoid conflicts. In this case, the query results in an
  # exception as the fields wouldn't have been defined in the ApiRecord
  return true if name == 'Lockstep::ApiRecord'

  attr = key.to_s
  Lockstep::Query::PREDICATES.keys.each do |predicate|
    if attr.end_with?(predicate)
      attr = attr.gsub(predicate, '')
      break
    end
  end
  valid = schema.has_key?(attr)
  raise StandardError, "Attribute '#{attr}' has not been defined for #{name}" if raise_exception && !valid

  valid
end

.where(*args) ⇒ Object

Find a Lockstep::ApiRecord object by chaining #where method calls.



546
547
548
# File 'app/concepts/lockstep/api_record.rb', line 546

def self.where(*args)
  query_builder.where(*args)
end

Instance Method Details

#==(other) ⇒ Object

if we are comparing objects, use id if they are both Lockstep::ApiRecord objects



996
997
998
999
1000
1001
1002
# File 'app/concepts/lockstep/api_record.rb', line 996

def ==(other)
  if other.class <= Lockstep::ApiRecord
    id == other.id
  else
    super
  end
end

#_read_attribute(attr) ⇒ Object

Alias of get_attribute



916
917
918
# File 'app/concepts/lockstep/api_record.rb', line 916

def _read_attribute(attr)
  get_attribute(attr)
end

#as_json(_options = {}) ⇒ Object



1156
1157
1158
# File 'app/concepts/lockstep/api_record.rb', line 1156

def as_json(_options = {})
  @attributes.merge(@unsaved_attributes).as_json
end

#attributesObject

provides access to @attributes for getting and setting



850
851
852
853
# File 'app/concepts/lockstep/api_record.rb', line 850

def attributes
  @attributes ||= self.class.class_attributes
  @attributes
end

#attributes=(value) ⇒ Object



855
856
857
858
859
860
861
862
# File 'app/concepts/lockstep/api_record.rb', line 855

def attributes=(value)
  if value.is_a?(Hash) && value.present?
    value.each do |k, v|
      send "#{k}=", v
    end
  end
  @attributes
end

#attributes_for_savingObject



724
725
726
727
728
729
730
731
732
733
# File 'app/concepts/lockstep/api_record.rb', line 724

def attributes_for_saving
  @unsaved_attributes = pointerize(@unsaved_attributes)
  put_attrs = @unsaved_attributes

  put_attrs = relations_for_saving(put_attrs)
  put_attrs.delete(id_ref)
  put_attrs.delete('created')
  put_attrs.delete('modified')
  put_attrs
end

#belongs_to_relationsObject



117
118
119
# File 'app/concepts/lockstep/api_record.rb', line 117

def belongs_to_relations
  @belongs_to_relations ||= {}
end

#clean?Boolean

Returns:

  • (Boolean)


845
846
847
# File 'app/concepts/lockstep/api_record.rb', line 845

def clean?
  !dirty?
end

#createObject



651
652
653
654
655
# File 'app/concepts/lockstep/api_record.rb', line 651

def create
  attrs = attributes_for_saving.transform_keys { |key| key.camelize(:lower) }
  resp = resource.post('', body: [attrs])
  result = post_result(resp)
end

#create_getters!(k, _v) ⇒ Object

Creates getter methods for model fields



250
251
252
253
254
255
256
# File 'app/concepts/lockstep/api_record.rb', line 250

def create_getters!(k, _v)
  unless respond_to? k.to_s
    self.class.send(:define_method, k.to_s) do
      get_attribute(k.to_s)
    end
  end
end

#create_setters!(k, _v) ⇒ Object

Creates setter methods for model fields



209
210
211
212
213
214
215
216
217
# File 'app/concepts/lockstep/api_record.rb', line 209

def create_setters!(k, _v)
  unless respond_to? "#{k}="
    self.class.send(:define_method, "#{k}=") do |val|
      set_attribute(k.to_s, val)

      val
    end
  end
end

#create_setters_and_getters!Object



258
259
260
261
262
263
# File 'app/concepts/lockstep/api_record.rb', line 258

def create_setters_and_getters!
  @attributes.each_pair do |k, v|
    create_setters!(k, v)
    create_getters!(k, v)
  end
end

#created_atObject



980
981
982
# File 'app/concepts/lockstep/api_record.rb', line 980

def created_at
  get_attribute('created')
end

#destroyObject



808
809
810
811
812
813
814
815
816
# File 'app/concepts/lockstep/api_record.rb', line 808

def destroy
  resp = resource.delete(id)
  if resp.code.to_s == '200'
    @attributes = {}
    @unsaved_attributes = {}
    return true
  end
  false
end

#dirty?Boolean

Returns:

  • (Boolean)


841
842
843
# File 'app/concepts/lockstep/api_record.rb', line 841

def dirty?
  @unsaved_attributes.length > 0
end

#enum_configObject



1080
1081
1082
# File 'app/concepts/lockstep/api_record.rb', line 1080

def enum_config
  self.class.enum_config
end

#get_attribute(k) ⇒ Object



864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
# File 'app/concepts/lockstep/api_record.rb', line 864

def get_attribute(k)
  attrs = @unsaved_attributes[k.to_s] ? @unsaved_attributes : @attributes
  case attrs[k]
  when Hash
    klass_name = attrs[k]['className']
    klass_name = 'User' if klass_name == '_User'
    case attrs[k]['__type']
    when 'Pointer'
      result = klass_name.to_s.constantize.find(attrs[k][id_ref])
    when 'Object'
      result = klass_name.to_s.constantize.new(attrs[k], false)
    when 'Date'
      result = DateTime.parse(attrs[k]['iso']).in_time_zone
    when 'File'
      result = attrs[k]['url']
    when 'Relation'
      objects_related_to_self = klass_name.constantize.where('$relatedTo' => {
        'object' => { '__type' => 'Pointer',
                      'className' => self.class.to_s, id_ref => id }, 'key' => k
      }).all
      attrs[k] = Lockstep::RelationArray.new self, objects_related_to_self, k, klass_name
      @unsaved_attributes[k] = Lockstep::RelationArray.new self, objects_related_to_self, k, klass_name
      result = @unsaved_attributes[k]
    end
  else
    # TODO: changed from @@has_many_relations to @@has_many_relations.keys as we have changed the has_many_relations
    #     from array to hash to capture more data points. Not sure of the impact of this.
    # relation will assign itself if an array, this will add to unsave_attributes
    if has_many_relations.keys.index(k.to_s)
      if attrs[k].nil?
        # result = nil
        result = load_association(:has_many, k)
      else
        @unsaved_attributes[k] = attrs[k].clone
        result = @unsaved_attributes[k]
      end
    elsif belongs_to_relations.keys.index(k.to_s)
      if attrs[k].nil?
        # result = nil
        result = load_association(:belongs_to, k)
      else
        @unsaved_attributes[k] = attrs[k].clone
        result = @unsaved_attributes[k]
      end
    else
      result = attrs[k.to_s]
    end
  end
  result
end

#has_many_relationsObject



941
942
943
# File 'app/concepts/lockstep/api_record.rb', line 941

def has_many_relations
  self.class.has_many_relations
end

#idObject

aliasing for idiomatic Ruby



968
969
970
971
972
# File 'app/concepts/lockstep/api_record.rb', line 968

def id
  get_attribute(id_ref)
rescue StandardError
  nil
end

#id_refObject



304
305
306
# File 'app/concepts/lockstep/api_record.rb', line 304

def id_ref
  self.class.id_ref
end

#instance_resourceObject

create RESTful resource for the specific Parse object sends requests to [base_uri]//[objectId]



617
618
619
# File 'app/concepts/lockstep/api_record.rb', line 617

def instance_resource
  self.class.resource[id.to_s]
end

#load_association(association_type, relation) ⇒ Object



1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
# File 'app/concepts/lockstep/api_record.rb', line 1004

def load_association(association_type, relation)
  @loaded_associations ||= []
  return nil if @loaded_associations.include?(relation)

  @loaded_associations << relation # Prevent the load_association from being called the 2nd time

  val = nil
  case association_type
  when :has_many
    relation_config = has_many_relations[relation]

    if relation_config[:loader].present?
      val = relation_config[:loader].call(self)
    else
      return val unless relation_config[:foreign_key].present? and relation_config[:primary_key].present?

      relation_klass = relation_config[:class_name].constantize
      return val unless relation_klass.model_name_uri.present?

      query = { relation_config[:foreign_key] => send(relation_config[:primary_key]) }
      if relation_config[:polymorphic]
        polymorphic_config = Lockstep::RelationArray.has_many_polymorphic_attributes(self,
                                                                                     relation_config[:polymorphic])
        query.merge!(polymorphic_config)
      end
      related_objects = relation_klass.send(:where, query).execute
      val = Lockstep::RelationArray.new self, related_objects, relation, relation_config[:class_name]
    end
  when :belongs_to
    relation_config = belongs_to_relations[relation]
    if relation_config[:loader].present?
      val = relation_config[:loader].call(self)
    else
      val = relation_config[:class_name].constantize.send(:find_by,
                                                          relation_config[:primary_key] => send(relation_config[:foreign_key]))
    end
  end

  set_attribute(relation, val)
  val
end

#merge_attributes(results) ⇒ Object

Merges in the return value of a save and resets the unsaved_attributes



669
670
671
672
673
674
675
676
677
678
679
680
# File 'app/concepts/lockstep/api_record.rb', line 669

def merge_attributes(results)
  results.transform_keys! { |key| key.underscore }
  @attributes.merge!(results)
  @attributes.merge!(@unsaved_attributes)

  # commenting for now as its a duplicate call
  # merge_relations
  @unsaved_attributes = {}

  create_setters_and_getters!
  @attributes
end

#merge_relationsObject



682
683
684
685
686
687
688
689
690
691
# File 'app/concepts/lockstep/api_record.rb', line 682

def merge_relations
  # KK 11-17-2012 The response after creation does not return full description of
  # the object nor the relations it contains. Make another request here.
  # TODO: @@has_many_relations structure has been changed from array to hash, need to evaluate the impact here
  if has_many_relations.keys.map { |relation| relation.to_s.to_sym }
    # TODO: make this a little smarter by checking if there are any Pointer objects in the objects attributes.
    # @attributes = self.class.to_s.constantize.where(:objectId => @attributes[self.id_ref]).first.attributes
    @attributes = self.class.to_s.constantize.where(id_ref => @attributes[id_ref]).first.attributes
  end
end

#model_base_uriObject

Gets the current instance’s parent class’s Parse.com base_uri



338
339
340
# File 'app/concepts/lockstep/api_record.rb', line 338

def model_base_uri
  self.class.send(:model_base_uri)
end

#new?Boolean

Returns:

  • (Boolean)


606
607
608
# File 'app/concepts/lockstep/api_record.rb', line 606

def new?
  !persisted?
end

#objectIdObject



974
975
976
977
978
# File 'app/concepts/lockstep/api_record.rb', line 974

def objectId
  get_attribute(id_ref)
rescue StandardError
  nil
end

#persisted?Boolean

Returns:

  • (Boolean)


598
599
600
601
602
603
604
# File 'app/concepts/lockstep/api_record.rb', line 598

def persisted?
  if id
    true
  else
    false
  end
end

#pointerize(hash) ⇒ Object



621
622
623
624
625
626
627
628
629
630
631
632
633
# File 'app/concepts/lockstep/api_record.rb', line 621

def pointerize(hash)
  new_hash = {}
  hash.each do |k, v|
    new_hash[k] = if v.respond_to?(:to_pointer)
                    v.to_pointer
                  elsif v.is_a?(Date) || v.is_a?(Time) || v.is_a?(DateTime)
                    self.class.to_date_object(v)
                  else
                    v
                  end
  end
  new_hash
end

#post_result(resp) ⇒ Object



693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
# File 'app/concepts/lockstep/api_record.rb', line 693

def post_result(resp)
  if resp.code.to_s == '200' || resp.code.to_s == '201'
    body = JSON.parse(resp.body)
    # Create method always responds with an array, whereas update responds with the object
    body = body.first if body.is_a?(Array)

    merge_attributes(body)

    true
  elsif resp.code.to_s == '400'
    error_response = JSON.parse(resp.body)
    errors = error_response['errors']
    errors.each do |key, messages|
      attribute = key.split('.').last&.underscore
      messages.each do |message|
        self.errors.add attribute, ": #{message}"
      end
    end
  else
    error_response = JSON.parse(resp.body)
    pe = if error_response['error']
           Lockstep::Error.new(error_response['code'], error_response['error'])
         else
           Lockstep::Error.new(resp.code.to_s)
         end
    self.errors.add(pe.code.to_s.to_sym, pe.msg)
    error_instances << pe
    false
  end
end

#primary_keyObject



963
964
965
# File 'app/concepts/lockstep/api_record.rb', line 963

def primary_key
  id_ref
end

#relations_for_saving(put_attrs) ⇒ Object



735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
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
# File 'app/concepts/lockstep/api_record.rb', line 735

def relations_for_saving(put_attrs)
  all_add_item_queries = {}
  all_remove_item_queries = {}
  @unsaved_attributes.each_pair do |key, value|
    next unless value.is_a? Array

    # Go through the array in unsaved and check if they are in array in attributes (saved stuff)
    add_item_ops = []
    @unsaved_attributes[key].each do |item|
      found_item_in_saved = false
      @attributes[key].each do |item_in_saved|
        if !!(defined? item.attributes) && item.attributes[id_ref] == item_in_saved.attributes[id_ref]
          found_item_in_saved = true
        end
      end

      next unless !found_item_in_saved && !!(defined? item.id)

      # need to send additem operation to parse
      put_attrs.delete(key) # arrays should not be sent along with REST to parse api
      add_item_ops << { '__type' => 'Pointer', 'className' => item.class.to_s, id_ref => item.id }
    end
    unless add_item_ops.empty?
      all_add_item_queries.merge!({ key => { '__op' => 'Add',
                                             'objects' => add_item_ops } })
    end

    # Go through saved and if it isn't in unsaved perform a removeitem operation
    remove_item_ops = []
    unless @unsaved_attributes.empty?
      @attributes[key].each do |item|
        found_item_in_unsaved = false
        @unsaved_attributes[key].each do |item_in_unsaved|
          if !!(defined? item.attributes) && item.attributes[id_ref] == item_in_unsaved.attributes[id_ref]
            found_item_in_unsaved = true
          end
        end

        if !found_item_in_unsaved && !!(defined? item.id)
          # need to send removeitem operation to parse
          remove_item_ops << { '__type' => 'Pointer', 'className' => item.class.to_s, id_ref => item.id }
        end
      end
    end
    unless remove_item_ops.empty?
      all_remove_item_queries.merge!({ key => { '__op' => 'Remove',
                                                'objects' => remove_item_ops } })
    end
  end

  # TODO: figure out a more elegant way to get this working. the remove_item merge overwrites the add.
  # Use a seperate query to add objects to the relation.
  # if !all_add_item_queries.empty?
  #  #result = self.instance_resource.put(all_add_item_queries.to_json, {:content_type => "application/json"}) do |resp, req, res, &block|
  #  #  return puts(resp, req, res, false, &block)
  #  #end
  #  puts result
  # end

  put_attrs.merge!(all_add_item_queries) unless all_add_item_queries.empty?
  put_attrs.merge!(all_remove_item_queries) unless all_remove_item_queries.empty?
  put_attrs
end

#reloadObject



830
831
832
833
834
835
836
837
838
839
# File 'app/concepts/lockstep/api_record.rb', line 830

def reload
  return false if new?

  fresh_object = self.class.find(id)
  @attributes = {}
  @attributes.update(fresh_object.instance_variable_get('@attributes'))
  @unsaved_attributes = {}

  self
end

#resourceObject

delegate from Class method



611
612
613
# File 'app/concepts/lockstep/api_record.rb', line 611

def resource
  self.class.resource
end

#saveObject



635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
# File 'app/concepts/lockstep/api_record.rb', line 635

def save
  if valid?
    run_callbacks :save do
      if new?
        create
      else
        update
      end
    end
  else
    false
  end
rescue StandardError
  false
end

#schemaObject



75
76
77
# File 'app/concepts/lockstep/api_record.rb', line 75

def schema
  self.class.schema
end

#set_attribute(k, v) ⇒ Object



920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
# File 'app/concepts/lockstep/api_record.rb', line 920

def set_attribute(k, v)
  if v.is_a?(Date) || v.is_a?(Time) || v.is_a?(DateTime)
    v = self.class.to_date_object(v)
    # elsif v.respond_to?(:to_pointer)
    #   v = v.to_pointer
  elsif (type = schema[k])
    # Typecast the result value using dry-types
    v = type[v]
  elsif v.present? and (enum = enum_config[k]).present? and enum.keys.include?(v.to_s)
    v = enum[v]
  end

  @unsaved_attributes[k.to_s] = v unless v == @attributes[k.to_s] # || @unsaved_attributes[k.to_s]
  @attributes[k.to_s] = v
  v
end

#to_json(options = {}) ⇒ Object



1152
1153
1154
# File 'app/concepts/lockstep/api_record.rb', line 1152

def to_json(options = {})
  as_json(options).to_json
end

#to_pointerObject



196
197
198
199
# File 'app/concepts/lockstep/api_record.rb', line 196

def to_pointer
  klass_name = self.class.model_name.to_s
  { '__type' => 'Pointer', 'className' => klass_name.to_s, id_ref => id }
end

#update(attributes = {}) ⇒ Object



657
658
659
660
661
662
663
664
665
666
# File 'app/concepts/lockstep/api_record.rb', line 657

def update(attributes = {})
  attributes = HashWithIndifferentAccess.new(attributes)

  @unsaved_attributes.merge!(attributes)
  # put_attrs = attributes_for_saving.to_json

  attrs = attributes_for_saving.transform_keys { |key| key.camelize(:lower) }
  resp = resource.patch(id, body: attrs)
  result = post_result(resp)
end

#update_attribute(key, value) ⇒ Object



803
804
805
806
# File 'app/concepts/lockstep/api_record.rb', line 803

def update_attribute(key, value)
  send(key.to_s + '=', value)
  update
end

#update_attributes(attributes = {}) ⇒ Object



799
800
801
# File 'app/concepts/lockstep/api_record.rb', line 799

def update_attributes(attributes = {})
  update(attributes)
end

#updated_atObject



984
985
986
# File 'app/concepts/lockstep/api_record.rb', line 984

def updated_at
  get_attribute('modified')
end

#validate_enumObject



1117
1118
1119
1120
1121
1122
1123
1124
# File 'app/concepts/lockstep/api_record.rb', line 1117

def validate_enum
  enum_config.each do |attribute, values_map|
    value = get_attribute(attribute)
    next if value.nil?

    errors.add attribute, 'has an invalid value' unless values_map.values.include?(value)
  end
end