synced 0.0.1 → 0.0.2
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 +4 -4
- data/README.md +107 -15
- data/lib/synced/engine.rb +7 -1
- data/lib/synced/engine/has_synced_data.rb +41 -0
- data/lib/synced/engine/model.rb +74 -0
- data/lib/synced/engine/synchronizer.rb +188 -0
- data/lib/synced/version.rb +1 -1
- metadata +19 -5
- data/app/models/synced/synchronization.rb +0 -4
- data/db/migrate/20140621143737_create_synced_synchronizations.rb +0 -10
- data/lib/synced/engine/lib/has_synced_data.rb +0 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 129cd901e2a89c56c4854ebc844b1f37f57833e3
|
4
|
+
data.tar.gz: c52f215a8f82e22919adfc6925db0e9fbde894f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 59b45c2d36ed714e375e2d34eabe2d57ba62453aad252a4a8c6cec61f134fc692c8692476bfa5c530334ad536a48199edbde2cf372f2ca3b746aa4ffbf1b75eb
|
7
|
+
data.tar.gz: 77a485f2007ce67c0f01be365622a770b41c01f96b240212fa87985e495cb0e2fbba594ca146c38cf0199d6e7ccc86a681ee58307684064512578f3e3cb30398
|
data/README.md
CHANGED
@@ -1,12 +1,17 @@
|
|
1
1
|
# Synced
|
2
2
|
|
3
|
-
Synced is a Rails Engine that helps you keep local models synchronized with
|
3
|
+
Synced is a Rails Engine that helps you keep local models synchronized with
|
4
|
+
their BookingSync representation.
|
4
5
|
|
5
|
-
Note: This synchronization is in one way only, from BookingSync to your
|
6
|
+
Note: This synchronization is in one way only, from BookingSync to your
|
7
|
+
application. If you want to do a 2 way synchronization, you will need to
|
8
|
+
implement it yourself using
|
9
|
+
[BookingSync-API](https://github.com/BookingSync/bookingsync-api)
|
6
10
|
|
7
11
|
## Requirements
|
8
12
|
|
9
|
-
This engine requires BookingSync API `>= 0.0.17`, Rails `>= 4.0.0` and
|
13
|
+
This engine requires BookingSync API `>= 0.0.17`, Rails `>= 4.0.0` and
|
14
|
+
Ruby `>= 2.0.0`.
|
10
15
|
|
11
16
|
## Documentation
|
12
17
|
|
@@ -14,24 +19,19 @@ This engine requires BookingSync API `>= 0.0.17`, Rails `>= 4.0.0` and Ruby `>=
|
|
14
19
|
|
15
20
|
## Installation
|
16
21
|
|
17
|
-
Synced works with BookingSync API 0.0.17 onwards, Rails 4.0 onwards and Ruby
|
22
|
+
Synced works with BookingSync API 0.0.17 onwards, Rails 4.0 onwards and Ruby
|
23
|
+
2.0 onwards. To get started, add it to your Gemfile with:
|
18
24
|
|
19
25
|
```ruby
|
20
26
|
gem 'synced'
|
21
27
|
```
|
22
28
|
|
23
|
-
|
24
|
-
|
25
|
-
```console
|
26
|
-
rake synced:install:migrations
|
27
|
-
```
|
28
|
-
|
29
|
-
Then, generate a migration to add Synced fields for the model you want to synchronize:
|
29
|
+
Generate a migration to add Synced fields for the model you want to synchronize:
|
30
30
|
|
31
31
|
Example:
|
32
32
|
```console
|
33
|
-
rails g migration AddSyncedFieldsToRentals synced_id:integer:index
|
34
|
-
synced_updated_at:datetime
|
33
|
+
rails g migration AddSyncedFieldsToRentals synced_id:integer:index \
|
34
|
+
synced_data:text synced_updated_at:datetime
|
35
35
|
```
|
36
36
|
|
37
37
|
and migrate:
|
@@ -40,11 +40,103 @@ and migrate:
|
|
40
40
|
rake db:migrate
|
41
41
|
```
|
42
42
|
|
43
|
-
And
|
43
|
+
And `synced` statement to the model you want to keep in sync.
|
44
|
+
|
45
|
+
Example:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
class Rental < ActiveRecord::Base
|
49
|
+
synced
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
Run synchronization with given remote rentals
|
54
|
+
|
55
|
+
Example:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
Rental.synchronize(remote: remote_rentals)
|
59
|
+
```
|
60
|
+
|
61
|
+
Run rentals synchronization in website scope
|
44
62
|
|
45
63
|
Example:
|
64
|
+
|
46
65
|
```ruby
|
66
|
+
Rental.synchronize(remote: remote_rentals, scope: website)
|
67
|
+
```
|
68
|
+
|
69
|
+
## Custom fields for storing remote object data.
|
70
|
+
|
71
|
+
By default synced stores remote object in the following db columns.
|
72
|
+
|
73
|
+
`synced_id` - ID of the remote object
|
74
|
+
`synced_data` - Whole remote object is serialized into this attribute
|
75
|
+
`synced_all_at` - Synchronization time of the local object when using
|
76
|
+
updated_since param
|
77
|
+
|
78
|
+
You can configure your own fields in `synced` declaration in your model.
|
79
|
+
|
80
|
+
```
|
47
81
|
class Rental < ActiveRecord::Base
|
48
|
-
|
82
|
+
synced id_key: :remote_id, data_key: :remote_data, synced_all_at_key: :remote_all_synced_at
|
49
83
|
end
|
50
84
|
```
|
85
|
+
|
86
|
+
## Local attributes
|
87
|
+
|
88
|
+
All remote data is stored in `synced_data`, however sometimes it's useful to have some attributes directly in your model. You can use `local_attributes` for that.
|
89
|
+
|
90
|
+
```
|
91
|
+
class Rental < ActiveRecord::Base
|
92
|
+
synced local_attributes: [:name, :size]
|
93
|
+
end
|
94
|
+
```
|
95
|
+
|
96
|
+
This assumes that model has name and size attributes. On every sychronization these two attributes will be assigned with value of `remote_object.name` and `remote_object.size` appropriately.
|
97
|
+
|
98
|
+
## Disabling synchronization for selected fields.
|
99
|
+
|
100
|
+
In some cases you only need one attribute to be synchronized and nothing more.
|
101
|
+
By default even when using local_attributes, whole remote object will be
|
102
|
+
saved in the `synced_data` and its updated_at in the `synced_all_at`.
|
103
|
+
This may take additonal space in the database.
|
104
|
+
In order to disable synchronizing these fields, set their names in the `synced` declaration to nil, as in the below example:
|
105
|
+
|
106
|
+
```
|
107
|
+
class Rental < ActiveRecord::Base
|
108
|
+
synced data_key: nil, synced_all_at_key: nil
|
109
|
+
end
|
110
|
+
```
|
111
|
+
|
112
|
+
You cannot disable synchronizing `synced_id` as it's required to match local
|
113
|
+
objects with the remote ones.
|
114
|
+
|
115
|
+
## Associations
|
116
|
+
|
117
|
+
It's possible to synchronize objects together with it's associations. For that
|
118
|
+
you need to
|
119
|
+
|
120
|
+
1. Specify associations you want to synchronize within `synced`
|
121
|
+
declaration of the parent model
|
122
|
+
2. Add `synced` declaration to the associated model
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
class Location < ActiveRecord::Base
|
126
|
+
synced associations: :photos
|
127
|
+
has_many :photos
|
128
|
+
end
|
129
|
+
|
130
|
+
class Photo < ActiveRecord::Base
|
131
|
+
synced
|
132
|
+
belongs_to :location
|
133
|
+
end
|
134
|
+
```
|
135
|
+
|
136
|
+
Then run synchronization of the parent objects. Every of the remote_locations
|
137
|
+
objects needs to respond to `remote_location[:photos]` from where data for
|
138
|
+
photos association will be taken.
|
139
|
+
|
140
|
+
```ruby
|
141
|
+
Location.synchronize(remote: remote_locations)
|
142
|
+
```
|
data/lib/synced/engine.rb
CHANGED
@@ -7,7 +7,13 @@ module Synced
|
|
7
7
|
end
|
8
8
|
|
9
9
|
config.to_prepare do
|
10
|
-
require "synced/engine/
|
10
|
+
require "synced/engine/has_synced_data"
|
11
|
+
end
|
12
|
+
|
13
|
+
ActiveSupport.on_load :active_record do
|
14
|
+
extend Synced::Engine::Model
|
11
15
|
end
|
12
16
|
end
|
13
17
|
end
|
18
|
+
|
19
|
+
require "synced/engine/model"
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'hashie'
|
2
|
+
|
3
|
+
# Provide a serialized attribute for models. This attribute is `synced_data_key`
|
4
|
+
# which by default is `:synced_data`. This is a friendlier alternative to
|
5
|
+
# `serialize` with respect to dirty attributes.
|
6
|
+
module Synced::Engine::HasSyncedData
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
class SyncedData < Hashie::Mash; end
|
9
|
+
|
10
|
+
included do
|
11
|
+
if synced_data_key
|
12
|
+
define_method "#{synced_data_key}=" do |object|
|
13
|
+
write_attribute synced_data_key, dump(object)
|
14
|
+
end
|
15
|
+
|
16
|
+
define_method synced_data_key do
|
17
|
+
instance_variable_get("@#{synced_data_key}") ||
|
18
|
+
instance_variable_set("@#{synced_data_key}",
|
19
|
+
SyncedData.new(loaded_synced_data))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def loaded_synced_data
|
27
|
+
if data = read_attribute(synced_data_key)
|
28
|
+
load data
|
29
|
+
else
|
30
|
+
{}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def dump(object)
|
35
|
+
JSON.dump object
|
36
|
+
end
|
37
|
+
|
38
|
+
def load(source)
|
39
|
+
JSON.load source
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require "synced/engine/synchronizer"
|
2
|
+
|
3
|
+
module Synced::Engine::Model
|
4
|
+
# Enables synced for ActiveRecord model.
|
5
|
+
#
|
6
|
+
# @param options [Hash] Configuration options for synced. They are inherited
|
7
|
+
# by subclasses, but can be overwritten in the subclass.
|
8
|
+
# @option options [Symbol] id_key: attribute name under which
|
9
|
+
# remote object's ID is stored, default is :synced_id.
|
10
|
+
# @option options [Symbol] synced_all_at_key: attribute name under which
|
11
|
+
# last synchronization time is stored, default is :synced_all_at. It's only
|
12
|
+
# used when only_updated option is enabled.
|
13
|
+
# @option options [Boolean] only_updated: If true requests to API will take
|
14
|
+
# advantage of updated_since param and fetch only created/changed/deleted
|
15
|
+
# remote objects
|
16
|
+
# @option options [Symbol] data_key: attribute name under which remote
|
17
|
+
# object's data is stored.
|
18
|
+
# @option options [Array] local_attributes: Array of attributes in the remote
|
19
|
+
# object which will be mapped to local object attributes.
|
20
|
+
def synced(options = {})
|
21
|
+
class_attribute :synced_id_key, :synced_all_at_key, :synced_data_key,
|
22
|
+
:synced_local_attributes, :synced_associations, :synced_only_updated
|
23
|
+
self.synced_id_key = options.fetch(:id_key, :synced_id)
|
24
|
+
self.synced_all_at_key = options.fetch(:synced_all_at_key,
|
25
|
+
:synced_all_at)
|
26
|
+
self.synced_data_key = options.fetch(:data_key, :synced_data)
|
27
|
+
self.synced_local_attributes = options.fetch(:local_attributes, [])
|
28
|
+
self.synced_associations = options.fetch(:associations, [])
|
29
|
+
self.synced_only_updated = options.fetch(:only_updated, false)
|
30
|
+
include Synced::Engine::HasSyncedData
|
31
|
+
end
|
32
|
+
|
33
|
+
# Performs synchronization of given remote objects to local database.
|
34
|
+
#
|
35
|
+
# @param remote [Array] - Remote objects to be synchronized with local db. If
|
36
|
+
# it's nil then synchronizer will make request on it's own.
|
37
|
+
# @param model_class [Class] - ActiveRecord model class to which remote objects
|
38
|
+
# will be synchronized.
|
39
|
+
# @param scope [ActiveRecord::Base] - Within this object scope local objects
|
40
|
+
# will be synchronized. By default it's model_class.
|
41
|
+
# @param remove [Boolean] - If it's true all local objects within
|
42
|
+
# current scope which are not present in the remote array will be destroyed.
|
43
|
+
# If only_updated is enabled, ids of objects to be deleted will be taken
|
44
|
+
# from the meta part. By default if cancel_at column is present, all
|
45
|
+
# missing local objects will be canceled with cancel_all,
|
46
|
+
# if it's missing, all will be destroyed with destroy_all.
|
47
|
+
# You can also force method to remove local objects by passing it
|
48
|
+
# to remove: :mark_as_missing.
|
49
|
+
# @example Synchronizing amenities
|
50
|
+
#
|
51
|
+
# Amenity.synchronize(remote: [remote_amenity1, remote_amenity2])
|
52
|
+
#
|
53
|
+
# @example Synchronizing rentals within given website. This will
|
54
|
+
# create/remove/update rentals only within website.
|
55
|
+
# It requires relation website.rentals to exist.
|
56
|
+
#
|
57
|
+
# Rental.synchronize(remote: remote_rentals, scope: website)
|
58
|
+
#
|
59
|
+
def synchronize(remote: nil, model_class: self, scope: nil, remove: false)
|
60
|
+
options = {
|
61
|
+
scope: scope,
|
62
|
+
id_key: synced_id_key,
|
63
|
+
synced_all_at_key: synced_all_at_key,
|
64
|
+
data_key: synced_data_key,
|
65
|
+
remove: remove,
|
66
|
+
local_attributes: synced_local_attributes,
|
67
|
+
associations: synced_associations,
|
68
|
+
only_updated: synced_only_updated
|
69
|
+
}
|
70
|
+
synchronizer = Synced::Engine::Synchronizer.new(remote, model_class,
|
71
|
+
options)
|
72
|
+
synchronizer.perform
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
# Synchronizer class which performs actual synchronization between
|
2
|
+
# local database and given array of remote objects
|
3
|
+
class Synced::Engine::Synchronizer
|
4
|
+
attr_reader :id_key
|
5
|
+
|
6
|
+
# Initializes a new Synchronizer
|
7
|
+
#
|
8
|
+
# @param remote_objects [Array|NilClass] Array of objects to be synchronized
|
9
|
+
# with local database. Objects need to respond to at least :id message.
|
10
|
+
# If it's nil, then synchronizer will fetch the remote objects on it's own.
|
11
|
+
# @param model_class [Class] ActiveRecord model class from which local objects
|
12
|
+
# will be created.
|
13
|
+
# @param options [Hash]
|
14
|
+
# @option options [Symbol] scope: Within this object scope local objects
|
15
|
+
# will be synchronized. By default it's model_class.
|
16
|
+
# @option options [Symbol] id_key: attribute name under which
|
17
|
+
# remote object's ID is stored, default is :synced_id.
|
18
|
+
# @option options [Symbol] synced_all_at_key: attribute name under which
|
19
|
+
# remote object's sync time is stored, default is :synced_all_at
|
20
|
+
# @option options [Symbol] data_key: attribute name under which remote
|
21
|
+
# object's data is stored.
|
22
|
+
# @option options [Array] local_attributes: Array of attributes in the remote
|
23
|
+
# object which will be mapped to local object attributes.
|
24
|
+
# @option options [Boolean] remove: If it's true all local objects within
|
25
|
+
# current scope which are not present in the remote array will be destroyed.
|
26
|
+
# If only_updated is enabled, ids of objects to be deleted will be taken
|
27
|
+
# from the meta part. By default if cancel_at column is present, all
|
28
|
+
# missing local objects will be canceled with cancel_all,
|
29
|
+
# if it's missing, all will be destroyed with destroy_all.
|
30
|
+
# You can also force method to remove local objects by passing it
|
31
|
+
# to remove: :mark_as_missing.
|
32
|
+
# @option options [Boolean] only_updated: If true requests to API will take
|
33
|
+
# advantage of updated_since param and fetch only created/changed/deleted
|
34
|
+
# remote objects
|
35
|
+
def initialize(remote_objects, model_class, options = {})
|
36
|
+
@model_class = model_class
|
37
|
+
@scope = options[:scope]
|
38
|
+
@id_key = options[:id_key]
|
39
|
+
@synced_all_at_key = options[:synced_all_at_key]
|
40
|
+
@data_key = options[:data_key]
|
41
|
+
@remove = options[:remove]
|
42
|
+
@only_updated = options[:only_updated]
|
43
|
+
@local_attributes = Array(options[:local_attributes])
|
44
|
+
@associations = Array(options[:associations])
|
45
|
+
@remote_objects = Array(remote_objects) if remote_objects
|
46
|
+
@request_performed = false
|
47
|
+
end
|
48
|
+
|
49
|
+
def perform
|
50
|
+
relation_scope.transaction do
|
51
|
+
remove_relation.send(remove_strategy) if @remove
|
52
|
+
|
53
|
+
remote_objects.map do |remote|
|
54
|
+
local_object = local_object_by_remote_id(remote.id) || relation_scope.new
|
55
|
+
local_object.attributes = default_attributes_mapping(remote)
|
56
|
+
local_object.attributes = local_attributes_mapping(remote)
|
57
|
+
local_object.save! if local_object.changed?
|
58
|
+
local_object.tap do |local_object|
|
59
|
+
@associations.each do |association|
|
60
|
+
klass = association.to_s.classify.constantize
|
61
|
+
klass.synchronize(remote: remote[association], scope: local_object,
|
62
|
+
remove: @remove)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end.tap do |local_objects|
|
66
|
+
if updated_since_enabled? && @request_performed
|
67
|
+
relation_scope.update_all(@synced_all_at_key => Time.now)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def local_attributes_mapping(remote)
|
76
|
+
Hash[@local_attributes.map { |k| [k, remote[k]] }]
|
77
|
+
end
|
78
|
+
|
79
|
+
def default_attributes_mapping(remote)
|
80
|
+
{}.tap do |attributes|
|
81
|
+
attributes[@id_key] = remote.id
|
82
|
+
attributes[@data_key] = remote if @data_key
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Returns relation within which local objects are created/edited and removed
|
87
|
+
# If no scope is provided, the relation_scope will be class on which
|
88
|
+
# .synchronize method is called.
|
89
|
+
# If scope is provided, like: account, then relation_scope will be a relation
|
90
|
+
# account.rentals (given we run .synchronize on Rental class)
|
91
|
+
#
|
92
|
+
# @return [ActiveRecord::Relation|Class]
|
93
|
+
def relation_scope
|
94
|
+
@scope ? @scope.send(resource_name) : @model_class
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns api client from the closest possible source.
|
98
|
+
#
|
99
|
+
# @raise [BookingSync::API::Unauthorized] - On unauthorized user
|
100
|
+
# @return [BookingSync::API::Client] BookingSync API client
|
101
|
+
def api
|
102
|
+
closest = [@scope, @scope.class, @model_class].detect do |o|
|
103
|
+
o.respond_to?(:api)
|
104
|
+
end
|
105
|
+
closest && closest.api || raise(MissingAPIClient.new(@scope, @model_class))
|
106
|
+
end
|
107
|
+
|
108
|
+
def local_object_by_remote_id(remote_id)
|
109
|
+
local_objects.find { |l| l.attributes[id_key.to_s] == remote_id }
|
110
|
+
end
|
111
|
+
|
112
|
+
def local_objects
|
113
|
+
@local_objects ||= relation_scope.where(id_key => remote_objects_ids).to_a
|
114
|
+
end
|
115
|
+
|
116
|
+
def remote_objects_ids
|
117
|
+
@remote_objects_ids ||= remote_objects.map(&:id)
|
118
|
+
end
|
119
|
+
|
120
|
+
def remote_objects
|
121
|
+
@remote_objects ||= fetch_remote_objects
|
122
|
+
end
|
123
|
+
|
124
|
+
def deleted_remote_objects_ids
|
125
|
+
api.last_response.meta[:deleted_ids]
|
126
|
+
end
|
127
|
+
|
128
|
+
def fetch_remote_objects
|
129
|
+
api.get("/#{resource_name}", api_request_options).tap do
|
130
|
+
@request_performed = true
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def api_request_options
|
135
|
+
{}.tap do |options|
|
136
|
+
options[:include] = @associations if @associations.present?
|
137
|
+
options[:updated_since] = minimum_updated_at if updated_since_enabled?
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def minimum_updated_at
|
142
|
+
relation_scope.minimum(@synced_all_at_key)
|
143
|
+
end
|
144
|
+
|
145
|
+
def updated_since_enabled?
|
146
|
+
@only_updated && @synced_all_at_key
|
147
|
+
end
|
148
|
+
|
149
|
+
def resource_name
|
150
|
+
@model_class.to_s.tableize
|
151
|
+
end
|
152
|
+
|
153
|
+
def remove_strategy
|
154
|
+
@remove == true ? default_remove_strategy : @remove
|
155
|
+
end
|
156
|
+
|
157
|
+
def default_remove_strategy
|
158
|
+
if @model_class.column_names.include?("canceled_at")
|
159
|
+
:cancel_all
|
160
|
+
else
|
161
|
+
:destroy_all
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def remove_relation
|
166
|
+
if @only_updated
|
167
|
+
relation_scope.where(id_key => deleted_remote_objects_ids)
|
168
|
+
else
|
169
|
+
relation_scope.where.not(id_key => remote_objects_ids)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
class MissingAPIClient < StandardError
|
174
|
+
def initialize(scope, model_class)
|
175
|
+
@scope = scope
|
176
|
+
@model_class = model_class
|
177
|
+
end
|
178
|
+
|
179
|
+
def message
|
180
|
+
if @scope
|
181
|
+
%Q{Missing BookingSync API client in #{@scope} object or
|
182
|
+
#{@scope.class} class}
|
183
|
+
else
|
184
|
+
%Q{Missing BookingSync API client in #{@model_class} class}
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
data/lib/synced/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: synced
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sebastien Grosjean
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-07-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: timecop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
97
111
|
description: Keep your BookingSync Application synced with BookingSync.
|
98
112
|
email:
|
99
113
|
- dev@bookingsync.com
|
@@ -104,12 +118,12 @@ files:
|
|
104
118
|
- MIT-LICENSE
|
105
119
|
- README.md
|
106
120
|
- Rakefile
|
107
|
-
- app/models/synced/synchronization.rb
|
108
121
|
- config/routes.rb
|
109
|
-
- db/migrate/20140621143737_create_synced_synchronizations.rb
|
110
122
|
- lib/synced.rb
|
111
123
|
- lib/synced/engine.rb
|
112
|
-
- lib/synced/engine/
|
124
|
+
- lib/synced/engine/has_synced_data.rb
|
125
|
+
- lib/synced/engine/model.rb
|
126
|
+
- lib/synced/engine/synchronizer.rb
|
113
127
|
- lib/synced/version.rb
|
114
128
|
homepage: https://github.com/BookingSync/synced
|
115
129
|
licenses:
|
@@ -1,37 +0,0 @@
|
|
1
|
-
require 'hashie'
|
2
|
-
|
3
|
-
module Synced
|
4
|
-
# Provide a serialized `bs_data` attribute for models. This is a friendlier
|
5
|
-
# alternative to `serialize` with respect to dirty attributes.
|
6
|
-
module HasSyncedData
|
7
|
-
class SyncedData < Hashie::Mash; end
|
8
|
-
|
9
|
-
# Serialize and set remote data from `object`.
|
10
|
-
def synced_data=(object)
|
11
|
-
write_attribute :synced_data, dump(object)
|
12
|
-
ensure
|
13
|
-
@synced_data = nil
|
14
|
-
end
|
15
|
-
|
16
|
-
# Return remote data as a cached instance.
|
17
|
-
def synced_data
|
18
|
-
@synced_data ||= SyncedData.new loaded_synced_data
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
def loaded_synced_data
|
24
|
-
load read_attribute(:synced_data)
|
25
|
-
rescue
|
26
|
-
{}
|
27
|
-
end
|
28
|
-
|
29
|
-
def dump(object)
|
30
|
-
JSON.dump object
|
31
|
-
end
|
32
|
-
|
33
|
-
def load(source)
|
34
|
-
JSON.load source
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|