serialized_synced_data.rb
2.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
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_chain field_data, :sync_default
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_chain "#{field_data}=", :prepare
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_chain field_data, :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? ActiveRecord::Base
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