synced 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5b1d111a0f8399a92dc2e05d16a7f5d2ec1b483f
4
- data.tar.gz: 5e294cabc9c1f81592269017b74b6463b554b91e
3
+ metadata.gz: e53235ec845a40357c1ae3610807ca571cec8807
4
+ data.tar.gz: 9e1b1289380aafc9a0a08b8f940a773b4308ade2
5
5
  SHA512:
6
- metadata.gz: b93a1b2a3485ccc1280356f17a6f76bada7a6a39314f4f5b0c44e10779418d638b957ca5f8a49136b7e3dc0484f9805af522134cc85c68934d170f76289338d3
7
- data.tar.gz: f52a4a789d434ae88fcc9f3e60f5f6f3350e139995ed39e90d120befb113ce2b7218ea03a468701ad99d3bb46133819b12e0456e4d973c109675fcc45957b9d5
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
@@ -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, :id_key,
33
- :include, :local_attributes, :mapper, :only_updated, :remove,
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
- self.synced_id_key = options.fetch(:id_key, :synced_id)
39
- self.synced_all_at_key = options.fetch(:synced_all_at_key,
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 = options.fetch(:data_key,
44
+ self.synced_data_key = options.fetch(:data_key,
42
45
  synced_column_presence(:synced_data))
43
- self.synced_local_attributes = options.fetch(:local_attributes, [])
44
- self.synced_associations = options.fetch(:associations, [])
45
- self.synced_only_updated = options.fetch(: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 = options.fetch(:mapper, nil)
48
- self.synced_remove = options.fetch(:remove, false)
49
- self.synced_include = options.fetch(:include, [])
50
- self.synced_fields = options.fetch(: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: synced_id_key,
92
- synced_data_key: synced_data_key,
93
- synced_all_at_key: synced_all_at_key,
94
- data_key: synced_data_key,
95
- local_attributes: synced_local_attributes,
96
- associations: synced_associations,
97
- only_updated: synced_only_updated,
98
- mapper: synced_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
@@ -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 = model_class
42
- @scope = options[:scope]
43
- @id_key = options[:id_key]
44
- @synced_all_at_key = options[:synced_all_at_key]
45
- @data_key = options[:data_key]
46
- @remove = options[:remove]
47
- @only_updated = options[:only_updated]
48
- @include = options[:include]
49
- @local_attributes = options[:local_attributes]
50
- @api = options[:api]
51
- @mapper = options[:mapper].respond_to?(:call) ?
52
- options[:mapper].call : options[:mapper]
53
- @fields = options[:fields]
54
- @remove = options[:remove]
55
- @associations = Array(options[:associations])
56
- @remote_objects = Array(options[:remote]) unless options[:remote].nil?
57
- @request_performed = false
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
- if @local_attributes.is_a?(Hash)
96
- Hash[
97
- @local_attributes.map do |k, v|
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
@@ -1,3 +1,3 @@
1
1
  module Synced
2
- VERSION = "1.0.2"
2
+ VERSION = "1.0.3"
3
3
  end
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.2
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-08-21 00:00:00.000000000 Z
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