syncano 3.1.4 → 4.0.0.alpha
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 +7 -0
- data/.gitignore +4 -1
- data/.rspec +2 -0
- data/.rubocop.yml +3 -0
- data/.ruby-version +1 -0
- data/Gemfile +25 -1
- data/Guardfile +22 -4
- data/README.md +68 -447
- data/Rakefile +48 -5
- data/circle.yml +10 -0
- data/lib/active_attr/dirty.rb +3 -17
- data/lib/active_attr/typecasting/hash_typecaster.rb +34 -0
- data/lib/active_attr/typecasting_override.rb +29 -0
- data/lib/syncano.rb +53 -92
- data/lib/syncano/api.rb +13 -0
- data/lib/syncano/connection.rb +97 -0
- data/lib/syncano/model/associations.rb +121 -0
- data/lib/syncano/{active_record/association → model/associations}/base.rb +5 -5
- data/lib/syncano/{active_record/association → model/associations}/belongs_to.rb +6 -6
- data/lib/syncano/{active_record/association → model/associations}/has_many.rb +15 -9
- data/lib/syncano/{active_record/association → model/associations}/has_one.rb +4 -4
- data/lib/syncano/model/base.rb +257 -0
- data/lib/syncano/{active_record → model}/callbacks.rb +16 -13
- data/lib/syncano/{active_record → model}/scope_builder.rb +53 -69
- data/lib/syncano/query_builder.rb +19 -129
- data/lib/syncano/resources.rb +126 -0
- data/lib/syncano/resources/base.rb +304 -300
- data/lib/syncano/resources/collection.rb +19 -223
- data/lib/syncano/resources/space.rb +29 -0
- data/lib/syncano/schema.rb +86 -0
- data/lib/syncano/schema/attribute_definition.rb +83 -0
- data/lib/syncano/schema/resource_definition.rb +36 -0
- data/lib/syncano/scope.rb +10 -0
- data/lib/syncano/version.rb +3 -4
- data/spec/integration/syncano_spec.rb +228 -0
- data/spec/spec_helper.rb +15 -9
- data/spec/unit/api_spec.rb +5 -0
- data/spec/unit/connection_spec.rb +137 -0
- data/spec/unit/query_builder_spec.rb +75 -0
- data/spec/unit/resources/collection_spec.rb +36 -0
- data/spec/unit/resources/space_spec.rb +28 -0
- data/spec/unit/resources_base_spec.rb +185 -0
- data/spec/unit/schema/attribute_definition_spec.rb +18 -0
- data/spec/unit/schema/resource_definition_spec.rb +25 -0
- data/spec/unit/schema_spec.rb +3532 -0
- data/spec/unit/syncano_spec.rb +63 -0
- data/syncano.gemspec +8 -14
- metadata +85 -210
- data/lib/generators/syncano/install_generator.rb +0 -17
- data/lib/generators/syncano/templates/initializers/syncano.rb +0 -7
- data/lib/syncano/active_record/associations.rb +0 -112
- data/lib/syncano/active_record/base.rb +0 -318
- data/lib/syncano/batch_queue.rb +0 -58
- data/lib/syncano/batch_queue_element.rb +0 -33
- data/lib/syncano/clients/base.rb +0 -123
- data/lib/syncano/clients/rest.rb +0 -79
- data/lib/syncano/clients/sync.rb +0 -164
- data/lib/syncano/errors.rb +0 -17
- data/lib/syncano/jimson_client.rb +0 -66
- data/lib/syncano/packets/auth.rb +0 -27
- data/lib/syncano/packets/base.rb +0 -70
- data/lib/syncano/packets/call.rb +0 -34
- data/lib/syncano/packets/call_response.rb +0 -33
- data/lib/syncano/packets/error.rb +0 -19
- data/lib/syncano/packets/message.rb +0 -30
- data/lib/syncano/packets/notification.rb +0 -39
- data/lib/syncano/packets/ping.rb +0 -12
- data/lib/syncano/resources/admin.rb +0 -26
- data/lib/syncano/resources/api_key.rb +0 -108
- data/lib/syncano/resources/data_object.rb +0 -316
- data/lib/syncano/resources/folder.rb +0 -88
- data/lib/syncano/resources/notifications/base.rb +0 -103
- data/lib/syncano/resources/notifications/create.rb +0 -20
- data/lib/syncano/resources/notifications/destroy.rb +0 -20
- data/lib/syncano/resources/notifications/message.rb +0 -9
- data/lib/syncano/resources/notifications/update.rb +0 -24
- data/lib/syncano/resources/project.rb +0 -96
- data/lib/syncano/resources/role.rb +0 -11
- data/lib/syncano/resources/subscription.rb +0 -12
- data/lib/syncano/resources/user.rb +0 -65
- data/lib/syncano/response.rb +0 -22
- data/lib/syncano/sync_connection.rb +0 -133
- data/spec/admins_spec.rb +0 -16
- data/spec/api_keys_spec.rb +0 -34
- data/spec/collections_spec.rb +0 -67
- data/spec/data_objects_spec.rb +0 -113
- data/spec/folders_spec.rb +0 -39
- data/spec/notifications_spec.rb +0 -43
- data/spec/projects_spec.rb +0 -35
- data/spec/roles_spec.rb +0 -13
- data/spec/sync_resources_spec.rb +0 -35
- data/spec/syncano_spec.rb +0 -9
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8fa33e829552d449652567e0ccf85426f4b31d9e
|
4
|
+
data.tar.gz: 877390535ea162188215684f8b7f58adb788b45b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8d4a6780ef77bda1100d9f09d5b833e9659890ca318442887a55d6aab5b6685cff320a13912376ba35547db826edd6ae82cec55be4b0a593274252941d68b415
|
7
|
+
data.tar.gz: 7077b7034ae4bf1189367c5582996579313d630330729d1cc800ab4ca5a71c3a5acf9a5558c8da89e51d391e633a9fce587bb7ae4fca9940a5fffa4092ced573
|
data/.gitignore
CHANGED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.1.5
|
data/Gemfile
CHANGED
@@ -1,4 +1,28 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
2
|
|
3
|
-
# Specify your gem's dependencies in syncano.gemspec
|
4
3
|
gemspec
|
4
|
+
|
5
|
+
group :console do
|
6
|
+
gem 'pry'
|
7
|
+
end
|
8
|
+
|
9
|
+
group :test do
|
10
|
+
gem 'dotenv'
|
11
|
+
gem 'rspec'
|
12
|
+
gem 'webmock'
|
13
|
+
gem 'shoulda-matchers', require: false
|
14
|
+
gem 'rspec-prof', git: 'https://github.com/sinisterchipmunk/rspec-prof.git'
|
15
|
+
end
|
16
|
+
|
17
|
+
group :tools do
|
18
|
+
gem 'guard'
|
19
|
+
gem 'guard-rspec'
|
20
|
+
gem 'guard-rubocop'
|
21
|
+
|
22
|
+
gem 'rubocop', require: false
|
23
|
+
|
24
|
+
platform :mri do
|
25
|
+
gem 'mutant'
|
26
|
+
gem 'mutant-rspec'
|
27
|
+
end
|
28
|
+
end
|
data/Guardfile
CHANGED
@@ -1,5 +1,23 @@
|
|
1
|
-
guard :rspec do
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
guard :rspec, cmd: 'bundle exec rspec' do
|
2
|
+
require 'guard/rspec/dsl'
|
3
|
+
dsl = Guard::RSpec::Dsl.new(self)
|
4
|
+
|
5
|
+
# Feel free to open issues for suggestions and improvements
|
6
|
+
|
7
|
+
# RSpec files
|
8
|
+
rspec = dsl.rspec
|
9
|
+
watch('spec/spec_helper.rb') { rspec.spec_dir }
|
10
|
+
watch('spec/**/*_spec.rb') { rspec.spec_dir }
|
11
|
+
watch(rspec.spec_files)
|
12
|
+
|
13
|
+
# Ruby files
|
14
|
+
ruby = dsl.ruby
|
15
|
+
dsl.watch_spec_files_for(ruby.lib_files)
|
16
|
+
|
17
|
+
watch(ruby.lib_files) { rspec.spec_dir }
|
5
18
|
end
|
19
|
+
|
20
|
+
# guard :rubocop do
|
21
|
+
# watch(%r{.+\.rb$})
|
22
|
+
# watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
|
23
|
+
# end
|
data/README.md
CHANGED
@@ -1,503 +1,124 @@
|
|
1
|
-
# Syncano
|
1
|
+
# Syncano 4.0 ruby gem
|
2
2
|
|
3
|
-
Syncano ruby gem provides communication with Syncano ([www.syncano.com](http://www.syncano.com)) via HTTPS RESTful interface and TCP sockets.
|
4
|
-
|
5
|
-
The full source code can be found on [Github](https://github.com/Syncano/syncano-ruby) - feel free to browse or contribute.
|
6
|
-
|
7
|
-
Click here to learn more about [Syncano](http://www.syncano.com) or [create an account](https://login.syncano.com/sign_up)!
|
8
3
|
|
9
4
|
## Installation
|
10
5
|
|
11
|
-
|
12
|
-
|
13
|
-
gem 'syncano', '~> 3.1'
|
14
|
-
|
15
|
-
And then execute:
|
16
|
-
|
17
|
-
$ bundle
|
18
|
-
|
19
|
-
Or install it yourself as:
|
20
|
-
|
21
|
-
$ gem install syncano -v 3.1.3
|
22
|
-
|
23
|
-
At the end generate initializer with api key and api instance name:
|
24
|
-
|
25
|
-
$ rails g syncano:install
|
26
|
-
|
27
|
-
Initializer is not obligatory - you can provide both parameters directly in the client's constructor.
|
28
|
-
|
29
|
-
## Usage
|
30
|
-
|
31
|
-
### Clients
|
32
|
-
|
33
|
-
There are two different class of clients. One for JSON RPC interface and one for socket connections with Sync Server. You can use both in quite similar way:
|
34
|
-
|
35
|
-
```ruby
|
36
|
-
client = Syncano.client
|
37
|
-
|
38
|
-
client = Syncano.sync_client
|
39
|
-
```
|
40
|
-
|
41
|
-
You can provide specific api credentials when you are initializing your client:
|
42
|
-
|
43
|
-
```ruby
|
44
|
-
client = Syncano.client(api_key: 'api key', instance_name: 'instance name')
|
45
|
-
|
46
|
-
client = Syncano.sync_client(api_key: 'api key', instance_name: 'instance name')
|
47
|
-
```
|
48
|
-
|
49
|
-
Sync client has some additional features like:
|
50
|
-
|
51
|
-
* managing connections
|
52
|
-
```ruby
|
53
|
-
client.connect
|
54
|
-
client.reconnect
|
55
|
-
client.disconnect
|
56
|
-
```
|
57
|
-
* managing callbacks for handling notifications (it is described later in this document)
|
58
|
-
|
59
|
-
#### User api key
|
60
|
-
|
61
|
-
If you want to use an user api key, you have to pass auth key or username and password to the client's constructor.
|
62
|
-
|
63
|
-
```ruby
|
64
|
-
client = Syncano.client(api_key: 'api key', instance_name: 'instance name', auth_key: 'auth key')
|
65
|
-
```
|
66
|
-
|
67
|
-
```ruby
|
68
|
-
client = Syncano.client(api_key: 'api key', instance_name: 'instance name', username: 'username', password: 'password')
|
69
|
-
```
|
70
|
-
|
71
|
-
### Resources
|
72
|
-
|
73
|
-
Syncano gem utilizes an ActiveRecord pattern for managing resources. You can use it in similar way with both type of clients.
|
74
|
-
|
75
|
-
Below is a list of standard methods implemented in resources.
|
76
|
-
|
77
|
-
* objects.all(parameters)
|
78
|
-
* objects.count(parameters)
|
79
|
-
* objects.first(parameters)
|
80
|
-
* objects.last(parameters)
|
81
|
-
* objects.find(id)
|
82
|
-
* objects.new(attributes)
|
83
|
-
* objects.create(attributes)
|
84
|
-
* object.update(attributes)
|
85
|
-
* object.save
|
86
|
-
* object.destroy
|
87
|
-
|
88
|
-
Some of resources do not implement all standard methods and others have some custom methods, ie. data_object.copy.
|
89
|
-
|
90
|
-
Every resource has attributes which can be accessed as a hash ie.:
|
91
|
-
|
92
|
-
* object[:attribute]
|
93
|
-
* object[:attribute] = 'value'
|
94
|
-
* object.attributes = { attribute: 'value' }
|
95
|
-
|
96
|
-
Below is a list of all implemented resources with information about what methods are implemented and usage examples.
|
97
|
-
|
98
|
-
#### Project
|
99
|
-
|
100
|
-
Implements all standard methods and following custom:
|
101
|
-
|
102
|
-
* project.authorize(api_key_id, permission)
|
103
|
-
|
104
|
-
##### Examples
|
105
|
-
|
106
|
-
* Getting all projects
|
107
|
-
|
108
|
-
```ruby
|
109
|
-
Syncano.projects.all
|
110
|
-
```
|
111
|
-
|
112
|
-
* Creating a project
|
113
|
-
|
114
|
-
```ruby
|
115
|
-
Syncano.projects.create(name: 'Project name')
|
116
|
-
```
|
117
|
-
|
118
|
-
* Updating a project
|
119
|
-
|
120
|
-
```ruby
|
121
|
-
project[:description] = 'Lorem ipsum'
|
122
|
-
project.save
|
123
|
-
```
|
124
|
-
|
125
|
-
* Authorizing user api key with read permission
|
126
|
-
|
127
|
-
```ruby
|
128
|
-
project.authorize(api_key_id, 'read_data')
|
129
|
-
```
|
130
|
-
|
131
|
-
#### Collection
|
132
|
-
|
133
|
-
Implements all standard methods and following custom:
|
134
|
-
|
135
|
-
* collections.find_by_key(collection_key)
|
136
|
-
* collection.activate
|
137
|
-
* collection.deactivate
|
138
|
-
* collection.add_tag(tag, weight, remove_others)
|
139
|
-
* collection.delete_tag(tag)
|
140
|
-
* collection.authorize(api_key_id, permission)
|
141
|
-
|
142
|
-
##### Examples
|
143
|
-
|
144
|
-
* Getting all
|
145
|
-
|
146
|
-
```ruby
|
147
|
-
project.collections.all
|
148
|
-
```
|
149
|
-
|
150
|
-
* Finding by key
|
6
|
+
Using gems:
|
151
7
|
|
152
|
-
```
|
153
|
-
|
154
|
-
```
|
155
|
-
|
156
|
-
* Activating
|
157
|
-
|
158
|
-
```ruby
|
159
|
-
collection.activate
|
160
|
-
```
|
161
|
-
|
162
|
-
* Adding tags
|
163
|
-
|
164
|
-
```ruby
|
165
|
-
collection1.add_tags(['tag1', 'tag2'], 3)
|
166
|
-
collection2.add_tags('tag3', 1, true)
|
8
|
+
```bash
|
9
|
+
$ gem install syncano --pre
|
167
10
|
```
|
168
11
|
|
169
|
-
|
170
|
-
|
171
|
-
Implements all standard methods and following custom:
|
172
|
-
|
173
|
-
* folders.find_by_name(folder_name)
|
174
|
-
* folder.authorize(api_key_id, permission)
|
175
|
-
|
176
|
-
Find method uses folder name as a key.
|
12
|
+
## First steps
|
177
13
|
|
178
|
-
|
179
|
-
|
180
|
-
* Getting one
|
181
|
-
|
182
|
-
```ruby
|
183
|
-
collection.folders.find(folder_name)
|
184
|
-
collection.folders.find_by_name(folder_name)
|
185
|
-
```
|
186
|
-
|
187
|
-
#### Data object
|
188
|
-
|
189
|
-
Implements all standard methods and following custom:
|
190
|
-
|
191
|
-
* data_objects.find_by_key(data_object_key)
|
192
|
-
* data_objects.move(data_object_ids, new_folder, new_state)
|
193
|
-
* data_object.move(new_folder, new_state)
|
194
|
-
* data_objects.copy(data_object_ids)
|
195
|
-
* data_object.copy
|
196
|
-
* data_object.add_parent(parent_id, remove_other)
|
197
|
-
* data_object.remove_parent(parent_id)
|
198
|
-
* data_object.add_child(parent_id, remove_other)
|
199
|
-
* data_object.remove_child(parent_id)
|
200
|
-
|
201
|
-
##### Examples
|
202
|
-
|
203
|
-
* Moving data object to the new folder
|
204
|
-
|
205
|
-
```ruby
|
206
|
-
data_object.move('new_folder')
|
207
|
-
```
|
14
|
+
After installation, you have to set a path for api root for syncano.
|
208
15
|
|
209
|
-
|
16
|
+
If you want to use staging, export:
|
210
17
|
|
211
|
-
```
|
212
|
-
|
18
|
+
```bash
|
19
|
+
$ export API_ROOT=https://v4.hydraengine.com
|
213
20
|
```
|
214
21
|
|
215
|
-
|
22
|
+
If you're less adventurous, use our production api servers:
|
216
23
|
|
217
|
-
```
|
218
|
-
|
24
|
+
```bash
|
25
|
+
$ export=API_ROOT=https://api.syncano.io
|
219
26
|
```
|
220
27
|
|
221
|
-
|
222
|
-
|
223
|
-
Implements all standard methods and following custom:
|
224
|
-
|
225
|
-
* admin.find_by_email(email)
|
226
|
-
|
227
|
-
#### Api key
|
228
|
-
|
229
|
-
Implements all standard methods.
|
230
|
-
|
231
|
-
#### Role
|
232
|
-
|
233
|
-
Implements only following standard methods:
|
234
|
-
|
235
|
-
* role.all
|
236
|
-
* role.first
|
237
|
-
* role.last
|
238
|
-
* role.count
|
239
|
-
|
240
|
-
#### User
|
241
|
-
|
242
|
-
Implements all standard methods.
|
243
|
-
|
244
|
-
### Batch requests
|
245
|
-
|
246
|
-
It is possible to make batch requests to the JSON RPC endpoint. You do not have to care about batch requests limits specified in the Syncano api docs. This library will care about queuing for you.
|
28
|
+
Ok, now we can start coding!
|
247
29
|
|
248
30
|
```ruby
|
249
|
-
|
250
|
-
responses = client.batch do |queue|
|
251
|
-
queue << collection.batch.save
|
252
|
-
queue << collection.data_objects.batch.create(title: 'Lorem ipsum')
|
253
|
-
queue.add(data_object.batch.destroy)
|
254
|
-
end
|
255
|
-
```
|
31
|
+
require 'syncano'
|
256
32
|
|
257
|
-
|
33
|
+
syncano = Syncano.connect(api_key: 'your-api-key')
|
258
34
|
|
259
|
-
|
260
|
-
Remember that batch responses do not change objects used in batch requests. If you want to see changes you have to reload them:
|
261
|
-
|
262
|
-
```ruby
|
263
|
-
collection.reload
|
35
|
+
syncano.instances.all.each { |instance| puts instance }
|
264
36
|
```
|
265
37
|
|
266
|
-
|
267
|
-
|
268
|
-
Main advantage of using Sync Server are real time notifications. This concept is well described in the Syncano api documentation.
|
38
|
+
You can either pass your API key to the connect method as above or set
|
39
|
+
`ENV['SYNCANO_API_KEY']` and call just `Syncano.connect`.
|
269
40
|
|
270
|
-
|
41
|
+
## API basics
|
271
42
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
project = client.project.find(project_id)
|
277
|
-
project.subscribe
|
278
|
-
```
|
279
|
-
|
280
|
-
If you want to stop receiving notifications, you have to unsubscribe:
|
281
|
-
```ruby
|
282
|
-
project.unsubscribe
|
283
|
-
```
|
43
|
+
Syncano API is a nested API - all the endpointes are scoped by an instances, ex.
|
44
|
+
codeboxes path is `/instance/your_instance_name/codeboxes/`. Syncano instances
|
45
|
+
is more less a schema is in relation databases. **Your instance name must be
|
46
|
+
unique across all existing Syncano instnaces, not only limitted to your account.**
|
284
47
|
|
285
|
-
You can also list all active subscriptions:
|
286
|
-
```ruby
|
287
|
-
client.subscriptions.all
|
288
|
-
```
|
289
48
|
|
290
|
-
|
49
|
+
# Instances
|
291
50
|
|
292
|
-
|
51
|
+
In order to do anything with Syncano, you have to create an instances. Choose a
|
52
|
+
globally unique name and call:
|
293
53
|
|
294
54
|
```ruby
|
295
|
-
|
296
|
-
|
297
|
-
end
|
298
|
-
```
|
299
|
-
|
300
|
-
Callbacks form a queue. You can add new callback to the end of the queue (like above) or to the beginning:
|
55
|
+
instances = syncano.instances.create name: 'my_instances_name'
|
56
|
+
instance.first
|
301
57
|
|
302
|
-
|
303
|
-
client.prepend_callback(:callback_name) do |notification|
|
304
|
-
p "We have received a new notification #{notification.inspect}! Yaaay!"
|
305
|
-
end
|
58
|
+
#=> #<Syncano::Resources::Instance created_at: Sun, 26 Apr 2015 18:09:46 +0000, description: "", metadata: {}, name: "my_instance_name", owner: nil, role: "full", updated_at: Sun, 26 Apr 2015 18:09:46 +0000>
|
306
59
|
```
|
307
60
|
|
308
|
-
|
309
|
-
|
310
|
-
```ruby
|
311
|
-
client.remove_callback(:callback_name)
|
312
|
-
```
|
61
|
+
# Classes and objects
|
313
62
|
|
314
|
-
|
63
|
+
In order to save objects in Syncano, first you need to create a class. A class
|
64
|
+
defines objects' attributes in the class' schema. The attribute definition has two
|
65
|
+
mandatory (`name`, `type`) and two optional fields (`filter_index`, `order_index`).
|
66
|
+
What these fields are for is rather obvious - `name` defines objects' attribute
|
67
|
+
name, and `type` defines type (you can read more about available types in the
|
68
|
+
[API docs](http://docs.syncano.com/v0.1/docs/instancesinstanceclasses-2)). `*_index`
|
69
|
+
fields are indexing. `order_index` allows you order returned collections,
|
70
|
+
`filter_index` allows filtering in a various ways. There will be a few examples
|
71
|
+
in this README, but you can read in the
|
72
|
+
[API docs](http://docs.syncano.com/v0.1/docs/filtering-data-objects).
|
315
73
|
|
316
74
|
```ruby
|
317
|
-
|
75
|
+
stock = instance.classes.create name: 'stock_items',
|
76
|
+
schema: [{ name: 'name', type: 'string',
|
77
|
+
filter_index: true },
|
78
|
+
{ name: 'amount', type: 'integer',
|
79
|
+
filter_index: true,
|
80
|
+
order_index: true }]
|
318
81
|
```
|
319
82
|
|
320
|
-
|
321
|
-
|
322
|
-
To send notification just create new notification object:
|
83
|
+
Once we have a class, we can start creating objects.
|
323
84
|
|
324
85
|
```ruby
|
325
|
-
|
86
|
+
chorizo = stock.objects.create name: 'Chorizo', amount: 100
|
87
|
+
black_pudding = stock.objects.create name: 'Black pudding', amount: 200
|
88
|
+
curry_wurts = stock.objects.create name: 'Curry wurst', amount: 150
|
89
|
+
kabanos = stock.objects.create name: 'Kabanos'
|
90
|
+
something = stock.objects.create amount: 3
|
326
91
|
```
|
327
92
|
|
328
|
-
|
93
|
+
Now we have a few items in stock, let's try filtering.
|
329
94
|
|
330
95
|
```ruby
|
331
|
-
|
96
|
+
stock.objects.all(order_by: '-amount', query: { amount: { _lte: 150 }, name: { _exists: true } })
|
97
|
+
#=> #<Syncano::Resources::Collection:0x007fc18b9c7698 @next=false, @prev=false, @collection=[#<Syncano::Resources::Object amount: 150, channel: nil, channel_room: nil, created_at: Mon, 27 Apr 2015 05:21:31 +0000, group: nil, group_permissions: "none", id: 12, name: "Curry wurst", other_permissions: "none", owner: nil, owner_permissions: "none", revision: 1, updated_at: Mon, 27 Apr 2015 05:21:31 +0000>, #<Syncano::Resources::Object amount: 100, channel: nil, channel_room: nil, created_at: Mon, 27 Apr 2015 05:21:30 +0000, group: nil, group_permissions: "none", id: 10, name: "Chorizo", other_permissions: "none", owner: nil, owner_permissions: "none", revision: 1, updated_at: Mon, 27 Apr 2015 05:21:30 +0000>]>
|
332
98
|
```
|
333
99
|
|
334
|
-
|
335
|
-
|
336
|
-
This library does not implement any validations. All errors from the api will cause throwing an exception.
|
337
|
-
It is thought that user will create his own validation mechanisms specific not only for restrictions imposed by the Syncano, but also for his own logic.
|
338
|
-
It can be compared to the exceptions after violating constraints in the MySQL database.
|
339
|
-
|
340
|
-
### Integration with Ruby on Rails
|
341
|
-
|
342
|
-
Syncano gem provides handy class for implementing model with ActiveRecord pattern. See example below:
|
100
|
+
Let's give `something` a name and try again.
|
343
101
|
|
344
102
|
```ruby
|
345
|
-
|
346
|
-
|
103
|
+
something.name = 'Unidentified sausage'
|
104
|
+
something.save
|
347
105
|
|
348
|
-
|
349
|
-
|
350
|
-
end
|
351
|
-
|
352
|
-
class Article < Syncano::ActiveRecord::Base
|
353
|
-
belongs_to :category
|
354
|
-
|
355
|
-
attribute :title, type: String
|
356
|
-
attribute :text, type: String
|
357
|
-
attribute :promoted, type: Integer, filterable: :data1
|
358
|
-
validates :title, presence: true
|
359
|
-
validates :text, presence: true
|
360
|
-
|
361
|
-
scope :promoted, -> { where('promoted = ?', 1) }
|
362
|
-
|
363
|
-
before_save :sanitize_content
|
364
|
-
|
365
|
-
private
|
366
|
-
|
367
|
-
def sanitize_content
|
368
|
-
self.title = Sanitize.clean(title)
|
369
|
-
self.text = Sanitize.clean(text)
|
370
|
-
end
|
371
|
-
end
|
372
|
-
```
|
373
|
-
|
374
|
-
#### Attributes
|
375
|
-
|
376
|
-
As you can see above every attribute has to be declared with a type. Every ActiveRecord class has also three standard attributes:
|
377
|
-
- :id, type: Integer
|
378
|
-
- :created_at, type: DateTime
|
379
|
-
- :updated_at, type: DateTime
|
380
|
-
|
381
|
-
There can be up to three filterable attributes (mapped to the Syncano data1, data2, data3 attributes), which can be used in where and order clauses. They always should have Integer type.
|
382
|
-
|
383
|
-
Attributes can be validated like in standard ActiveRecord.
|
384
|
-
|
385
|
-
#### Scopes and query building
|
386
|
-
|
387
|
-
You can sort and filter by filterable attributes:
|
388
|
-
|
389
|
-
```ruby
|
390
|
-
where('attribute1 > ? AND attribute2 <= ?', 0, 30).order('attribute3 ASC').where('attribute 2 > ?', 5)
|
391
|
-
```
|
392
|
-
|
393
|
-
As you can see methods can be chained.
|
394
|
-
|
395
|
-
#### Callbacks
|
396
|
-
|
397
|
-
There are available ten different callbacks fired in the following sequence:
|
398
|
-
|
399
|
-
1. before_validation
|
400
|
-
2. after_validation
|
401
|
-
3. before_save
|
402
|
-
4. before_create / before_update
|
403
|
-
5. after_create / after_save
|
404
|
-
6. after_save
|
405
|
-
|
406
|
-
1. before_destroy
|
407
|
-
2. after_destroy
|
408
|
-
|
409
|
-
#### Associations
|
410
|
-
|
411
|
-
There are three types of relations (belongs_to, has_one, has_many) which are based on Syncano parent - child mechanism.
|
412
|
-
|
413
|
-
##### belongs_to :category
|
414
|
-
|
415
|
-
Adds following methods:
|
416
|
-
|
417
|
-
```ruby
|
418
|
-
self.category
|
419
|
-
self.category = Category.first
|
420
|
-
self.category_id
|
421
|
-
self.category_id = Category.first.id
|
422
|
-
```
|
423
|
-
|
424
|
-
Remember to always declare belongs_to association! It creates proper attribute in model.
|
425
|
-
|
426
|
-
##### has_one :article
|
427
|
-
|
428
|
-
```ruby
|
429
|
-
self.article
|
430
|
-
self.article = Article.first # this method updates article object
|
431
|
-
self.build_article(article_attributes)
|
432
|
-
self.create_article(article_attributes)
|
433
|
-
```
|
434
|
-
|
435
|
-
##### has_many :articles
|
436
|
-
|
437
|
-
```ruby
|
438
|
-
self.articles
|
439
|
-
self.articles = Article.first(5) # this method updates each article object
|
440
|
-
self.articles << Article.first # this method updates article object
|
441
|
-
self.articles.build(article_attributes)
|
442
|
-
self.articles.create(article_attributes)
|
443
|
-
```
|
444
|
-
|
445
|
-
You can also call scope builder methods on has_many collection:
|
446
|
-
|
447
|
-
```ruby
|
448
|
-
self.articles.promoted.all
|
449
|
-
```
|
450
|
-
|
451
|
-
#### Other useful methods in examples
|
452
|
-
|
453
|
-
```ruby
|
454
|
-
Article.promoted.find(id)
|
455
|
-
Article.where('promoted = ?', 0).count
|
456
|
-
Article.since(min_id).before(max_id)
|
457
|
-
Article.since(Time.now - 10.days)
|
106
|
+
stock.objects.all(order_by: '-amount', query: { amount: { _lte: 150 }, name: { _exists: true } })
|
107
|
+
#=> #<Syncano::Resources::Collection:0x007fc18d58a628 @next=false, @prev=false, @collection=[#<Syncano::Resources::Object amount: 150, channel: nil, channel_room: nil, created_at: Mon, 27 Apr 2015 05:21:31 +0000, group: nil, group_permissions: \"none\", id: 12, name: \"Curry wurst\", other_permissions: \"none\", owner: nil, owner_permissions: \"none\", revision: 1, updated_at: Mon, 27 Apr 2015 05:21:31 +0000>, #<Syncano::Resources::Object amount: 100, channel: nil, channel_room: nil, created_at: Mon, 27 Apr 2015 05:21:30 +0000, group: nil, group_permissions: \"none\", id: 10, name: \"Chorizo\", other_permissions: \"none\", owner: nil, owner_permissions: \"none\", revision: 1, updated_at: Mon, 27 Apr 2015 05:21:30 +0000>, #<Syncano::Resources::Object amount: 3, channel: nil, channel_room: nil, created_at: Mon, 27 Apr 2015 05:30:18 +0000, group: nil, group_permissions: \"none\", id: 15, name: \"Unidentified sausage\", other_permissions: \"none\", owner: nil, owner_permissions: \"none\", revision: 2, updated_at: Mon, 27 Apr 2015 05:30:48 +0000>]>
|
458
108
|
```
|
459
109
|
|
460
|
-
|
110
|
+
Now it matches the query and appears in the result.
|
461
111
|
|
462
|
-
|
112
|
+
# Codeboxes
|
463
113
|
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
```
|
114
|
+
Codeboxes are small pieces of code that run on Syncano servers. You can run them
|
115
|
+
manually using the API, you can create a schedule to run them periodically, you
|
116
|
+
can create a Webhook (and optionally make it public) to run them from the web,
|
117
|
+
you can create a trigger to run one after a class' object is created, updated or
|
118
|
+
deleted. There are three runtimes available: Ruby, Python and Node. This gem is
|
119
|
+
available in Ruby runtime (just needs to be required).
|
471
120
|
|
472
|
-
or it can be overwritten in selected model:
|
473
121
|
|
474
|
-
```ruby
|
475
|
-
class Article < Syncano::ActiveRecord::Base
|
476
|
-
|
477
|
-
private
|
478
|
-
|
479
|
-
def self.collection
|
480
|
-
Syncano.client.project.first.collection.first
|
481
|
-
end
|
482
|
-
end
|
483
|
-
```
|
484
|
-
|
485
|
-
Folders are used as classes - each model as his own folder (ie. Articles). Folder is automatically created and used without any additional configuration, but you can customize convention by overwriting folder_name or folder method:
|
486
|
-
|
487
|
-
```ruby
|
488
|
-
class Article < Syncano::ActiveRecord::Base
|
489
|
-
|
490
|
-
private
|
491
|
-
|
492
|
-
def self.folder_name
|
493
|
-
'Posts'
|
494
|
-
end
|
495
|
-
|
496
|
-
def self.folder
|
497
|
-
collection.folders.find_by_name(folder_name)
|
498
|
-
end
|
499
|
-
end
|
500
|
-
```
|
501
122
|
|
502
123
|
## Contributing
|
503
124
|
|