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 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