synced 1.0.2 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +51 -0
- data/lib/synced/model.rb +29 -23
- data/lib/synced/synchronizer.rb +42 -26
- data/lib/synced/version.rb +1 -1
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e53235ec845a40357c1ae3610807ca571cec8807
|
4
|
+
data.tar.gz: 9e1b1289380aafc9a0a08b8f940a773b4308ade2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 30fb365ace28a5d26c29601a42d0f308c6a43fdafb0d872968bd797aea799da796a250a8eca45f02c2e43033f5ff8598a5162cb7361119e59777a372e58dcc34
|
7
|
+
data.tar.gz: 004235ba0a34d878c544665ba580bdf0fd643eac9d84e71421f783aaef5901095359923975608a5588ee7362867470faf615a496e513300a059c0faca57735d0
|
data/README.md
CHANGED
@@ -168,6 +168,39 @@ class Rental < ActiveRecord::Base
|
|
168
168
|
end
|
169
169
|
```
|
170
170
|
|
171
|
+
### Globalized attributes
|
172
|
+
|
173
|
+
Some of the API endpoints return strings in multiple languages.
|
174
|
+
When your app is also multilingual you might want take advantage of it
|
175
|
+
and import translations straight to model translations.
|
176
|
+
|
177
|
+
In order to import translations use `:globalized_attributes` attribute. It
|
178
|
+
assumes that your app is using Globalize 3 or newer and `:headline` is already
|
179
|
+
a translated attribute.
|
180
|
+
|
181
|
+
```ruby
|
182
|
+
class Rental < ActiveRecord::Base
|
183
|
+
synced globalized_attributes: :headline
|
184
|
+
translates :headline
|
185
|
+
end
|
186
|
+
```
|
187
|
+
|
188
|
+
Now headline will be saved for all translations provided by the API.
|
189
|
+
If given translation will be removed on the API side, it will set to nil
|
190
|
+
locally.
|
191
|
+
|
192
|
+
If you want to map remote field to a different local attribute,
|
193
|
+
specify mapping as a Hash instead of an Array.
|
194
|
+
|
195
|
+
```ruby
|
196
|
+
class Rental < ActiveRecord::Base
|
197
|
+
synced globalized_attributes: {headline: :description}
|
198
|
+
translates :headline
|
199
|
+
end
|
200
|
+
```
|
201
|
+
|
202
|
+
This will map remote `:description` to local `:headline` attribute.
|
203
|
+
|
171
204
|
## Partial updates (using updated since parameter)
|
172
205
|
|
173
206
|
Partial updates mean that first synchronization will copy all of the remote
|
@@ -182,6 +215,24 @@ NOTE: In order it to work, given endpoint needs to support updated_since
|
|
182
215
|
parameter. Check [API documentation](http://docs.api.bookingsync.com/reference/)
|
183
216
|
for given endpoint.
|
184
217
|
|
218
|
+
### Forcing local objects to be re-synced with the API
|
219
|
+
|
220
|
+
When you add a new column or change something in the synced attributes and you
|
221
|
+
are using partial updates, old local objects will not be re-synced with API
|
222
|
+
automatically. You need to reset `synced_all_at` column in order to force
|
223
|
+
re-syncing objects again on the next synchronization. In order to do that use
|
224
|
+
`reset_synced` method.
|
225
|
+
|
226
|
+
```ruby
|
227
|
+
Rental.reset_synced
|
228
|
+
```
|
229
|
+
|
230
|
+
You can use this method on a relation as well.
|
231
|
+
|
232
|
+
```ruby
|
233
|
+
account.rentals.reset_synced
|
234
|
+
```
|
235
|
+
|
185
236
|
## Disabling saving whole synced_data
|
186
237
|
|
187
238
|
If you don't need whole remote object to be stored in local object skip
|
data/lib/synced/model.rb
CHANGED
@@ -16,7 +16,7 @@ module Synced
|
|
16
16
|
# remote objects
|
17
17
|
# @option options [Symbol] data_key: attribute name under which remote
|
18
18
|
# object's data is stored.
|
19
|
-
# @option options [Array] local_attributes: Array of attributes in the remote
|
19
|
+
# @option options [Array|Hash] local_attributes: Array of attributes in the remote
|
20
20
|
# object which will be mapped to local object attributes.
|
21
21
|
# @option options [Boolean|Symbol] remove: If it's true all local objects
|
22
22
|
# within current scope which are not present in the remote array will be
|
@@ -27,27 +27,32 @@ module Synced
|
|
27
27
|
# if it's missing, all will be destroyed with destroy_all.
|
28
28
|
# You can also force method to remove local objects by passing it
|
29
29
|
# to remove: :mark_as_missing.
|
30
|
+
# @option options [Array|Hash] globalized_attributes: A list of attributes
|
31
|
+
# which will be mapped with their translations.
|
30
32
|
def synced(options = {})
|
31
33
|
options.symbolize_keys!
|
32
|
-
options.assert_valid_keys(:associations, :data_key, :fields,
|
33
|
-
:
|
34
|
-
:synced_all_at_key)
|
34
|
+
options.assert_valid_keys(:associations, :data_key, :fields,
|
35
|
+
:globalized_attributes, :id_key, :include, :local_attributes, :mapper,
|
36
|
+
:only_updated, :remove, :synced_all_at_key)
|
35
37
|
class_attribute :synced_id_key, :synced_all_at_key, :synced_data_key,
|
36
38
|
:synced_local_attributes, :synced_associations, :synced_only_updated,
|
37
|
-
:synced_mapper, :synced_remove, :synced_include, :synced_fields
|
38
|
-
|
39
|
-
self.
|
39
|
+
:synced_mapper, :synced_remove, :synced_include, :synced_fields,
|
40
|
+
:synced_globalized_attributes
|
41
|
+
self.synced_id_key = options.fetch(:id_key, :synced_id)
|
42
|
+
self.synced_all_at_key = options.fetch(:synced_all_at_key,
|
40
43
|
synced_column_presence(:synced_all_at))
|
41
|
-
self.synced_data_key
|
44
|
+
self.synced_data_key = options.fetch(:data_key,
|
42
45
|
synced_column_presence(:synced_data))
|
43
|
-
self.synced_local_attributes
|
44
|
-
self.synced_associations
|
45
|
-
self.synced_only_updated
|
46
|
+
self.synced_local_attributes = options.fetch(:local_attributes, [])
|
47
|
+
self.synced_associations = options.fetch(:associations, [])
|
48
|
+
self.synced_only_updated = options.fetch(:only_updated,
|
46
49
|
column_names.include?(synced_all_at_key.to_s))
|
47
|
-
self.synced_mapper
|
48
|
-
self.synced_remove
|
49
|
-
self.synced_include
|
50
|
-
self.synced_fields
|
50
|
+
self.synced_mapper = options.fetch(:mapper, nil)
|
51
|
+
self.synced_remove = options.fetch(:remove, false)
|
52
|
+
self.synced_include = options.fetch(:include, [])
|
53
|
+
self.synced_fields = options.fetch(:fields, [])
|
54
|
+
self.synced_globalized_attributes = options.fetch(:globalized_attributes,
|
55
|
+
[])
|
51
56
|
include Synced::HasSyncedData
|
52
57
|
end
|
53
58
|
|
@@ -88,14 +93,15 @@ module Synced
|
|
88
93
|
options[:include] = Array(synced_include) unless options.has_key?(:include)
|
89
94
|
options[:fields] = Array(synced_fields) unless options.has_key?(:fields)
|
90
95
|
options.merge!({
|
91
|
-
id_key:
|
92
|
-
synced_data_key:
|
93
|
-
synced_all_at_key:
|
94
|
-
data_key:
|
95
|
-
local_attributes:
|
96
|
-
associations:
|
97
|
-
only_updated:
|
98
|
-
mapper:
|
96
|
+
id_key: synced_id_key,
|
97
|
+
synced_data_key: synced_data_key,
|
98
|
+
synced_all_at_key: synced_all_at_key,
|
99
|
+
data_key: synced_data_key,
|
100
|
+
local_attributes: synced_local_attributes,
|
101
|
+
associations: synced_associations,
|
102
|
+
only_updated: synced_only_updated,
|
103
|
+
mapper: synced_mapper,
|
104
|
+
globalized_attributes: synced_globalized_attributes
|
99
105
|
})
|
100
106
|
Synced::Synchronizer.new(self, options).perform
|
101
107
|
end
|
data/lib/synced/synchronizer.rb
CHANGED
@@ -37,24 +37,27 @@ module Synced
|
|
37
37
|
# remote objects
|
38
38
|
# @option options [Module] mapper: Module class which will be used for
|
39
39
|
# mapping remote objects attributes into local object attributes
|
40
|
+
# @option options [Array|Hash] globalized_attributes: A list of attributes
|
41
|
+
# which will be mapped with their translations.
|
40
42
|
def initialize(model_class, options = {})
|
41
|
-
@model_class
|
42
|
-
@scope
|
43
|
-
@id_key
|
44
|
-
@synced_all_at_key
|
45
|
-
@data_key
|
46
|
-
@remove
|
47
|
-
@only_updated
|
48
|
-
@include
|
49
|
-
@local_attributes
|
50
|
-
@api
|
51
|
-
@mapper
|
52
|
-
|
53
|
-
@fields
|
54
|
-
@remove
|
55
|
-
@associations
|
56
|
-
@remote_objects
|
57
|
-
@request_performed
|
43
|
+
@model_class = model_class
|
44
|
+
@scope = options[:scope]
|
45
|
+
@id_key = options[:id_key]
|
46
|
+
@synced_all_at_key = options[:synced_all_at_key]
|
47
|
+
@data_key = options[:data_key]
|
48
|
+
@remove = options[:remove]
|
49
|
+
@only_updated = options[:only_updated]
|
50
|
+
@include = options[:include]
|
51
|
+
@local_attributes = attributes_as_hash(options[:local_attributes])
|
52
|
+
@api = options[:api]
|
53
|
+
@mapper = options[:mapper].respond_to?(:call) ?
|
54
|
+
options[:mapper].call : options[:mapper]
|
55
|
+
@fields = options[:fields]
|
56
|
+
@remove = options[:remove]
|
57
|
+
@associations = Array(options[:associations])
|
58
|
+
@remote_objects = Array(options[:remote]) unless options[:remote].nil?
|
59
|
+
@request_performed = false
|
60
|
+
@globalized_attributes = attributes_as_hash(options[:globalized_attributes])
|
58
61
|
end
|
59
62
|
|
60
63
|
def perform
|
@@ -69,6 +72,10 @@ module Synced
|
|
69
72
|
local_object = local_object_by_remote_id(remote.id) || relation_scope.new
|
70
73
|
local_object.attributes = default_attributes_mapping(remote)
|
71
74
|
local_object.attributes = local_attributes_mapping(remote)
|
75
|
+
if @globalized_attributes.present?
|
76
|
+
local_object.attributes = globalized_attributes_mapping(remote,
|
77
|
+
local_object.translations.translated_locales)
|
78
|
+
end
|
72
79
|
local_object.save! if local_object.changed?
|
73
80
|
local_object.tap do |local_object|
|
74
81
|
@associations.each do |association|
|
@@ -92,15 +99,9 @@ module Synced
|
|
92
99
|
private
|
93
100
|
|
94
101
|
def local_attributes_mapping(remote)
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
[k, v.respond_to?(:call) ? v.call(remote) : remote.send(v)]
|
99
|
-
end
|
100
|
-
]
|
101
|
-
else
|
102
|
-
Hash[Array(@local_attributes).map { |k| [k, remote.send(k)] }]
|
103
|
-
end
|
102
|
+
Hash[@local_attributes.map do |k, v|
|
103
|
+
[k, v.respond_to?(:call) ? v.call(remote) : remote.send(v)]
|
104
|
+
end]
|
104
105
|
end
|
105
106
|
|
106
107
|
def default_attributes_mapping(remote)
|
@@ -110,6 +111,16 @@ module Synced
|
|
110
111
|
end
|
111
112
|
end
|
112
113
|
|
114
|
+
def globalized_attributes_mapping(remote, used_locales)
|
115
|
+
empty = Hash[used_locales.map { |locale| [locale.to_s, nil] }]
|
116
|
+
{}.tap do |attributes|
|
117
|
+
@globalized_attributes.each do |local_attr, remote_attr|
|
118
|
+
translations = empty.merge(remote.send(remote_attr) || {})
|
119
|
+
attributes["#{local_attr}_translations"] = translations
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
113
124
|
# Returns relation within which local objects are created/edited and removed
|
114
125
|
# If no scope is provided, the relation_scope will be class on which
|
115
126
|
# .synchronize method is called.
|
@@ -213,6 +224,11 @@ module Synced
|
|
213
224
|
Synced.instrumenter.instrument(*args, &block)
|
214
225
|
end
|
215
226
|
|
227
|
+
def attributes_as_hash(attributes)
|
228
|
+
return attributes if attributes.is_a?(Hash)
|
229
|
+
Hash[Array(attributes).map { |name| [name, name] }]
|
230
|
+
end
|
231
|
+
|
216
232
|
class MissingAPIClient < StandardError
|
217
233
|
def initialize(scope, model_class)
|
218
234
|
@scope = scope
|
data/lib/synced/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: synced
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sebastien Grosjean
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-09-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -137,6 +137,20 @@ dependencies:
|
|
137
137
|
- - '>='
|
138
138
|
- !ruby/object:Gem::Version
|
139
139
|
version: '0'
|
140
|
+
- !ruby/object:Gem::Dependency
|
141
|
+
name: globalize
|
142
|
+
requirement: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - ~>
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: 4.0.2
|
147
|
+
type: :development
|
148
|
+
prerelease: false
|
149
|
+
version_requirements: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - ~>
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: 4.0.2
|
140
154
|
description: Keep your BookingSync Application synced with BookingSync.
|
141
155
|
email:
|
142
156
|
- dev@bookingsync.com
|