lib/undo/serializer/active_model.rb in undo-serializer-active_model-0.0.4 vs lib/undo/serializer/active_model.rb in undo-serializer-active_model-0.1.0
- old
+ new
@@ -1,66 +1,125 @@
-require "active_support"
-
module Undo
module Serializer
class ActiveModel
- def initialize(*args)
- options = args.extract_options!
- @serializer = args.first
- @serializer_source = options.fetch :serializer,
- ->(object) { object.active_model_serializer.new object }
+ def initialize(options = {})
+ load_options options
end
- def serialize(object)
- serializer(object).as_json
+ def serialize(object, options = {})
+ return object.map do |record|
+ serialize record, options
+ end if array? object
+
+ load_options options
+
+ attributes = serialize_attributes(object) || {}
+ associations = {}
+ Array(options[:include]).map do |association|
+ associations[association] = serialize(object.public_send association)
+ end
+ pk_attributes = symbolize_keys(attributes).select do |attribute|
+ primary_key_fields.include? attribute
+ end
+
+ {
+ attributes: attributes,
+ associations: associations,
+ meta: {
+ pk_attributes: pk_attributes,
+ class_name: object.class.name,
+ }
+ }
end
- def deserialize(hash)
- object_handler, data = hash.first
- return unless data.is_a? Hash
- data.stringify_keys!
+ def deserialize(object, options = {})
+ return object.map do |record|
+ deserialize record
+ end if array? object
- ActiveRecord::Base.transaction do
- initialize_object(object_handler, data).tap do |object|
- data.each do |field, value|
- next if "id" == field && object.persisted?
+ load_options options
- case field
- when /___(.*)/ then deserialize_association object, $1, value
- else deserialize_field object, field, value
- end
+ hash = symbolize_keys object
+ object_meta = hash.fetch :meta
+ associations = hash.fetch :associations
+ attributes = hash.fetch :attributes
+
+ with_transaction do
+ initialize_object(object_meta).tap do |object|
+ attributes.each do |field, value|
+ deserialize_field object, field, value
end
- object.save!
+ # QUESTION: Set associations? object.association_name = deserialize association ?
+ associations.each do |(association_name, association)|
+ deserialize association
+ end
+
+ persist object
end
end
-
end
private
- attr_reader :serializer_source
+ attr_reader :serialize_attributes_source,
+ :initialize_object_source,
+ :persist_object_source
- def serializer(object)
- @serializer ||= serializer_source.call object
+ def deserialize_field(object, field, value)
+ object.send "#{field}=", value # not public_send!
end
- def deserialize_association(object, association, values)
- Array.wrap(values).each do |value|
- deserialize object.public_send(association) => value
+ def initialize_object(meta)
+ object_class = constantize meta.fetch(:class_name)
+ pk_attributes = meta.fetch :pk_attributes
+
+ find_or_initialize object_class, pk_attributes
+ end
+
+ def with_transaction(&block)
+ if defined? ActiveRecord
+ ActiveRecord::Base.transaction(&block)
+ else
+ block.call
end
end
- def deserialize_field(object, field, value)
- object.send "#{field}=", value # not public_send!
+ def load_options(options)
+ @serialize_attributes_source = options.fetch :serialize_attributes, @serialize_attributes_source ||
+ ->(object) { object.attributes }
+
+ @initialize_object_source = options.fetch :find_or_initialize, @initialize_object_source ||
+ ->(object_class, pk_query) { object_class.respond_to?(:where) && object_class.where(pk_query).first || object_class.new(pk_query) }
+
+ @persist_object_source = options.fetch :persist, @persist_object_source ||
+ ->(object) { object.respond_to?(:save!) && object.save! }
+
+ @primary_key_fields = options.fetch :primary_key, @primary_key_fields || :id
end
- def initialize_object(object_handler, data)
- id = data.fetch "id"
- relation = case object_handler
- when String, Symbol then object_handler.to_s.camelize.constantize
- else object_handler end
+ def primary_key_fields
+ Array(@primary_key_fields)
+ end
- relation.where(id: id).first || relation.new(id: id)
+ def serialize_attributes(*args); serialize_attributes_source.call(*args) end
+ def find_or_initialize(*args); initialize_object_source.call(*args) end
+ def persist(*args); persist_object_source.call(*args) end
+
+ def array?(object)
+ object.respond_to?(:map) && ! object.is_a?(Hash)
+ end
+ # ActiveSupport methods
+ def symbolize_keys(hash)
+ hash.each_with_object({}) do |(key, value), result|
+ new_key = key.is_a?(String) ? key.to_sym : key
+ new_value = value.is_a?(Hash) ? symbolize_keys(value) : value
+
+ result[new_key] = new_value
+ end
+ end
+
+ def constantize(class_name)
+ class_name.split('::').inject(Kernel) { |object, name| object = object.const_get(name); object }
end
end
end
end