class Paquito::ActiveRecordCoder

Public Class Methods

dump(record) click to toggle source
# File lib/paquito/active_record_coder.rb, line 8
def dump(record)
  instances = InstanceTracker.new
  serialized_associations = serialize_associations(record, instances)
  serialized_records = instances.map { |r| serialize_record(r) }
  [serialized_associations, *serialized_records]
end
load(payload) click to toggle source
# File lib/paquito/active_record_coder.rb, line 15
def load(payload)
  instances = InstanceTracker.new
  serialized_associations, *serialized_records = payload
  serialized_records.each { |attrs| instances.push(deserialize_record(*attrs)) }
  deserialize_associations(serialized_associations, instances)
end

Private Class Methods

attributes_for_database(record) click to toggle source
# File lib/paquito/active_record_coder.rb, line 91
def attributes_for_database(record)
  attributes = record.attributes_for_database
  attributes.transform_values! { |attr| attr.is_a?(::ActiveModel::Type::Binary::Data) ? attr.to_s : attr }
  attributes
end
deserialize_associations(payload, instances) click to toggle source
# File lib/paquito/active_record_coder.rb, line 62
def deserialize_associations(payload, instances)
  return unless payload

  id, associations = payload
  record = instances.fetch(id)

  associations&.each do |name, serialized_target|
    begin
      association = record.association(name)
    rescue ActiveRecord::AssociationNotFoundError
      raise AssociationMissingError, "undefined association: #{name}"
    end

    target = if association.reflection.collection?
      serialized_target.map! { |serialized_record| deserialize_associations(serialized_record, instances) }
    else
      deserialize_associations(serialized_target, instances)
    end

    association.target = target
  end

  record
end
deserialize_record(class_name, attributes_from_database) click to toggle source
# File lib/paquito/active_record_coder.rb, line 97
def deserialize_record(class_name, attributes_from_database)
  begin
    klass = Object.const_get(class_name)
  rescue NameError
    raise ClassMissingError, "undefined class: #{class_name}"
  end
  klass.instantiate(attributes_from_database)
end
serialize_associations(record, instances) click to toggle source

Records without associations, or which have already been visited before, are serialized by their id alone.

Records with associations are serialized as a two-element array including their id and the record’s association cache.

# File lib/paquito/active_record_coder.rb, line 30
def serialize_associations(record, instances)
  return unless record

  if (id = instances.lookup(record))
    payload = id
  else
    payload = instances.push(record)

    cached_associations = record.class.reflect_on_all_associations.select do |reflection|
      record.association_cached?(reflection.name)
    end

    unless cached_associations.empty?
      serialized_associations = cached_associations.map do |reflection|
        association = record.association(reflection.name)

        serialized_target = if reflection.collection?
          association.target.map { |target_record| serialize_associations(target_record, instances) }
        else
          serialize_associations(association.target, instances)
        end

        [reflection.name, serialized_target]
      end

      payload = [payload, serialized_associations]
    end
  end

  payload
end
serialize_record(record) click to toggle source
# File lib/paquito/active_record_coder.rb, line 87
def serialize_record(record)
  [record.class.name, attributes_for_database(record)]
end