plugins/orders/lib/serialized_synced_data.rb
module SerializedSyncedData
def self.prepare_data _hash
return {} unless _hash
hash = {}; _hash.each do |key, value|
next if value.blank?
hash[key.to_sym] = value
end
hash
end
module ClassMethods
def sync_serialized_field field, &block
class_attribute :serialized_synced_fields unless self.respond_to? :serialized_synced_fields
self.serialized_synced_fields ||= []
self.serialized_synced_fields << field
field_data = "#{field}_data".to_sym
field_data_without_sync = "#{field_data}_without_sync".to_sym
serialize field_data
before_save "fill_#{field_data}"
# Rails doesn't define getters/setter for attributes
if not self.method_defined? field_data and field_data.to_s.in? self.column_names
define_method field_data do
self[field_data] || {}
end
else
define_method "#{field_data}_with_sync_default" do
self.send("#{field_data}_without_sync_default") || {}
end
alias_method :field_data_without_sync, :field_data
alias_method :field_data, :field_data_with_sync
end
if not self.method_defined? "#{field_data}=" and field_data.to_s.in? self.column_names
define_method "#{field_data}=" do |value|
self[field_data] = SerializedSyncedData.prepare_data value
end
else
define_method "#{field_data}_with_prepare=" do |value|
self.send "#{field_data}_without_prepare=", SerializedSyncedData.prepare_data(value)
end
alias_method ("#{field_data}="_without_prepare).to_sym, :("#{field_data}=").to_sym
alias_method :("#{field_data}=").to_sym, ("#{field_data}="_with_prepare).to_sym
end
# return data from foreign registry if any data was synced yet
define_method "#{field_data}_with_sync" do
current_data = self.send field_data_without_sync
if current_data.present? then current_data else self.send "#{field}_synced_data" end
end
alias_method :field_data_without_sync, :field_data
alias_method :field_data, :field_data_with_sync
# get the data to sync as defined
define_method "#{field}_synced_data" do
source = self.send field
if block_given?
data = SerializedSyncedData.prepare_data instance_exec(source, &block)
elsif source.is_a? ApplicationRecord
data = SerializedSyncedData.prepare_data source.attributes
elsif source.is_a? Array
data = source.map{ |source| SerializedSyncedData.prepare_data source.attributes }
end || {}
end
define_method "sync_#{field_data}" do
value = self.send "#{field}_synced_data"
current = self.send field_data
value = current.deep_merge! value
self.send "#{field_data}=", value
end
define_method "fill_#{field_data}" do
return if self.send(field_data_without_sync).present?
self.send "sync_#{field_data}"
end
include InstanceMethods
end
end
module InstanceMethods
def sync_serialized_data
self.class.serialized_synced_fields.each do |field|
self.send "sync_#{field}_data"
end
end
end
end