sync_bumper 0.1.0
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/CHANGELOG.md +50 -0
- data/Gemfile +3 -0
- data/LICENSE +22 -0
- data/README.md +408 -0
- data/Rakefile +0 -0
- data/lib/generators/sync/install_generator.rb +13 -0
- data/lib/generators/sync/templates/sync_bumper.rb +10 -0
- data/lib/sync_bumper.rb +24 -0
- data/lib/sync_bumper/model.rb +93 -0
- metadata +80 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: eeb67b4ccf61e6b2c827757823f6c3409b204a0f
|
4
|
+
data.tar.gz: 1c00aeefec000c068ed4198c161fd84b9d1827a1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4a38eb4c7caa2151750ef0f6de38f2dbe0afb392a5e3f97fea70d1d691ab8eb3f4a8029238818773b719f0997275a2964e881d6ab104e624942c174d8d76796d
|
7
|
+
data.tar.gz: 6bf29354269289a5ee3836aeeeddfde38eb11bd3296df2128a74fcd3f8b2231878302438dbd58f53633190cc7582e9da342940cf2880f6422128d9cacff271c5
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# Version 0.2.3 - June 30, 2013
|
2
|
+
|
3
|
+
- Fixed Turbolinks issue where `page:restore` events no longer evaluate script tags in the body. The workaround re-evaluates all sync sript tags on page restore.
|
4
|
+
|
5
|
+
# Version 0.2.1 - May 27, 2013
|
6
|
+
|
7
|
+
- Add ability to narrow scope to custom channel for sync_new publishes
|
8
|
+
|
9
|
+
Example Usage:
|
10
|
+
|
11
|
+
View:
|
12
|
+
```erb
|
13
|
+
<%= sync_new partial: 'todo_list_row', resource: Todo.new, scope: [@project, :staff] %>
|
14
|
+
```
|
15
|
+
|
16
|
+
Controller/Model:
|
17
|
+
```ruby
|
18
|
+
sync_new @todo, scope: [@project, :staff]
|
19
|
+
```
|
20
|
+
|
21
|
+
|
22
|
+
# Version 0.2.0 - May 26, 2013
|
23
|
+
|
24
|
+
- Add ability to refetch partial from server to render within session context, ref: https://github.com/chrismccord/sync/issues/44
|
25
|
+
|
26
|
+
This solves the issues of syncing partials across different users when the partial requires the session's context (ie. current_user).
|
27
|
+
|
28
|
+
Ex:
|
29
|
+
View: Add `refetch: true` to sync calls, and place partial file in a 'refetch'
|
30
|
+
subdirectory in the model's sync view folder:
|
31
|
+
|
32
|
+
The partial file would be located in `app/views/sync/todos/refetch/_list_row.html.erb`
|
33
|
+
```erb
|
34
|
+
<% @project.todos.ordered.each do |todo| %>
|
35
|
+
<%= sync partial: 'list_row', resource: todo, refetch: true %>
|
36
|
+
<% end %>
|
37
|
+
<%= sync_new partial: 'list_row', resource: Todo.new, scope: @project, refetch: true %>
|
38
|
+
```
|
39
|
+
|
40
|
+
*Notes*
|
41
|
+
While this approach works very well for the cases it's needed, syncing without refetching should be used unless refetching is absolutely necessary for performance reasons. For example,
|
42
|
+
|
43
|
+
A sync update request is triggered on the server for a 'regular' sync'd partial with 100 listening clients:
|
44
|
+
- number of http requests 1
|
45
|
+
- number of renders 1, pushed out to all 100 clients via pubsub server.
|
46
|
+
|
47
|
+
|
48
|
+
A sync update request is triggered on the server for a 'refetch' sync'd partial with 100 listening clients:
|
49
|
+
- number of http requests 100
|
50
|
+
- number of renders 100, rendering each request in clients session context.
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Chris McCord
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
The Software shall be used for Good, not Evil.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,408 @@
|
|
1
|
+
# Sync
|
2
|
+
> This started as a thought experiment that is growing into a viable option for realtime Rails apps without ditching
|
3
|
+
the standard rails stack that we love and are so productive with for a heavy client side MVC framework.
|
4
|
+
|
5
|
+
|
6
|
+
Real-time partials with Rails. Sync lets you render partials for models that, with minimal code,
|
7
|
+
update in realtime in the browser when changes occur on the server.
|
8
|
+
|
9
|
+
#### Watch a screencast to see it in action
|
10
|
+
[](http://chrismccord.com/blog/2013/04/21/sync-realtime-rails-partials/)
|
11
|
+
|
12
|
+
In practice, one simply only needs to replace:
|
13
|
+
|
14
|
+
```erb
|
15
|
+
<%= render partial: 'user_row', locals: {user: @user} %>
|
16
|
+
```
|
17
|
+
|
18
|
+
with:
|
19
|
+
|
20
|
+
```erb
|
21
|
+
<%= sync partial: 'user_row', resource: @user %>
|
22
|
+
```
|
23
|
+
|
24
|
+
Then update views realtime automatically with the `sync` DSL or with a with a simple `sync_update(@user)` in the controller without any extra javascript or
|
25
|
+
configuration.
|
26
|
+
|
27
|
+
In addition to real-time updates, Sync also provides:
|
28
|
+
|
29
|
+
- Realtime removal of partials from the DOM when the sync'd model is destroyed in the controller via `sync_destroy(@user)`
|
30
|
+
- Realtime appending of newly created model's on scoped channels
|
31
|
+
- JavaScript/CoffeeScript hooks to override and extend element updates/appends/removes for partials
|
32
|
+
- Support for [Faye](http://faye.jcoglan.com/) and [Pusher](http://pusher.com)
|
33
|
+
|
34
|
+
## Requirements
|
35
|
+
|
36
|
+
- Ruby >= 1.9.2
|
37
|
+
- Rails 3 >= 3.1 or Rails 4
|
38
|
+
- jQuery >= 1.9
|
39
|
+
|
40
|
+
|
41
|
+
## Installation
|
42
|
+
|
43
|
+
#### 1) Add the gem to your `Gemfile`
|
44
|
+
|
45
|
+
#### Using Faye
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
gem 'faye'
|
49
|
+
gem 'thin', require: false
|
50
|
+
gem 'sync'
|
51
|
+
```
|
52
|
+
|
53
|
+
#### Using Pusher
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
gem 'pusher'
|
57
|
+
gem 'sync'
|
58
|
+
```
|
59
|
+
|
60
|
+
#### Install
|
61
|
+
|
62
|
+
```bash
|
63
|
+
$ bundle
|
64
|
+
$ rails g sync:install
|
65
|
+
```
|
66
|
+
|
67
|
+
#### 2) Require sync in your asset javascript manifest `app/assets/javascripts/application.js`:
|
68
|
+
|
69
|
+
```javascript
|
70
|
+
//= require sync
|
71
|
+
```
|
72
|
+
|
73
|
+
#### 3) Add the pubsub adapter's javascript to your application layout `app/views/layouts/application.html.erb`
|
74
|
+
|
75
|
+
```erb
|
76
|
+
<%= javascript_include_tag Sync.adapter_javascript_url %>
|
77
|
+
```
|
78
|
+
|
79
|
+
#### 4) Configure your pubsub server (Faye or Pusher)
|
80
|
+
|
81
|
+
|
82
|
+
#### Using [Faye](http://faye.jcoglan.com/) (self hosted)
|
83
|
+
|
84
|
+
Set your configuration in the generated `config/sync.yml` file, using the Faye adapter. Then run Faye alongside your app.
|
85
|
+
|
86
|
+
```bash
|
87
|
+
rackup sync.ru -E production
|
88
|
+
```
|
89
|
+
|
90
|
+
#### Using [Pusher](http://pusher.com) (SaaS)
|
91
|
+
|
92
|
+
Set your configuration in the generated `config/sync.yml` file, using the Pusher adapter. No extra process/setup.
|
93
|
+
|
94
|
+
## Current Caveats
|
95
|
+
The current implementation uses a DOM range query (jQuery's `nextUntil`) to match your partial's "element" in
|
96
|
+
the DOM. The way this selector works requires your sync'd partial to be wrapped in a root level html tag for that partial file.
|
97
|
+
For example, this parent view/sync partial approach would *not* work:
|
98
|
+
|
99
|
+
Given the sync partial `_todo_row.html.erb`:
|
100
|
+
|
101
|
+
```erb
|
102
|
+
Title:
|
103
|
+
<%= link_to todo.title, todo %>
|
104
|
+
```
|
105
|
+
|
106
|
+
And the parent view:
|
107
|
+
|
108
|
+
```erb
|
109
|
+
<table>
|
110
|
+
<tbody>
|
111
|
+
<tr>
|
112
|
+
<%= sync partial: 'todo_row', resource: @todo %>
|
113
|
+
</tr>
|
114
|
+
</tbody>
|
115
|
+
</table>
|
116
|
+
```
|
117
|
+
|
118
|
+
##### The markup *would need to change to*:
|
119
|
+
|
120
|
+
|
121
|
+
sync partial `_todo_row.html.erb`:
|
122
|
+
|
123
|
+
```erb
|
124
|
+
<tr> <!-- root level container for the partial required here -->
|
125
|
+
Title:
|
126
|
+
<%= link_to todo.title, todo %>
|
127
|
+
</tr>
|
128
|
+
```
|
129
|
+
|
130
|
+
And the parent view changed to:
|
131
|
+
|
132
|
+
```erb
|
133
|
+
<table>
|
134
|
+
<tbody>
|
135
|
+
<%= sync partial: 'todo_row', resource: @todo %>
|
136
|
+
</tbody>
|
137
|
+
</table>
|
138
|
+
```
|
139
|
+
|
140
|
+
I'm currently investigating true DOM ranges via the [Range](https://developer.mozilla.org/en-US/docs/DOM/range) object.
|
141
|
+
|
142
|
+
|
143
|
+
## 'Automatic' syncing through the sync DSL
|
144
|
+
|
145
|
+
In addition to calling explicit sync actions within controller methods, a
|
146
|
+
`sync` and `enable_sync` DSL has been added to ActionController::Base and ActiveRecord::Base to automate the syncing
|
147
|
+
approach in a controlled, threadsafe way.
|
148
|
+
|
149
|
+
### Example Controller/Model
|
150
|
+
```ruby
|
151
|
+
class TodosController < ApplicationController
|
152
|
+
|
153
|
+
enable_sync only: [:create, :update, :destroy]
|
154
|
+
...
|
155
|
+
end
|
156
|
+
|
157
|
+
class Todo < ActiveRecord::Base
|
158
|
+
|
159
|
+
belongs_to :project, counter_cache: true
|
160
|
+
has_many :comments, dependent: :destroy
|
161
|
+
|
162
|
+
sync :all, scope: :project
|
163
|
+
|
164
|
+
end
|
165
|
+
```
|
166
|
+
|
167
|
+
### Syncing outside of the controller
|
168
|
+
|
169
|
+
`Sync::Actions` can be included into any object wishing to perform sync
|
170
|
+
publishes for a given resource. Instead of using the the controller as
|
171
|
+
context for rendering, a Sync::Renderer instance is used. Since the Renderer
|
172
|
+
is not part of the request/response/session, it has no knowledge of the
|
173
|
+
current session (ie. current_user), so syncing from outside the controller
|
174
|
+
context will require some care that the partial can be rendered within a
|
175
|
+
sessionless context.
|
176
|
+
|
177
|
+
### Example Syncing from a background worker or rails console
|
178
|
+
```ruby
|
179
|
+
# Inside some script/worker
|
180
|
+
Sync::Model.enable do
|
181
|
+
Todo.first.update title: "This todo will be sync'd on save"
|
182
|
+
end
|
183
|
+
Todo.first.update title: "This todo will NOT be sync'd on save"
|
184
|
+
|
185
|
+
Sync::Model.enable!
|
186
|
+
Todo.first.update title: "This todo will be sync'd on save"
|
187
|
+
Todo.first.update title: "This todo will be sync'd on save"
|
188
|
+
Todo.first.update title: "This todo will be sync'd on save"
|
189
|
+
Sync::Model.disable!
|
190
|
+
Todo.first.update title: "This todo will NOT be sync'd on save"
|
191
|
+
```
|
192
|
+
|
193
|
+
## Custom Sync Views and javascript hooks
|
194
|
+
|
195
|
+
Sync allows you to hook into and override or extend all of the actions it performs when updating partials on the client side. When a sync partial is rendered, sync will instantiate a javascript View class based on the following order of lookup:
|
196
|
+
|
197
|
+
1. The camelized version of the concatenated snake case resource
|
198
|
+
and partial names.
|
199
|
+
2. The camelized version of the snake cased partial name.
|
200
|
+
|
201
|
+
#### Examples
|
202
|
+
|
203
|
+
partial name 'list_row', resource name 'todo', order of lookup:
|
204
|
+
|
205
|
+
1. Sync.TodoListRow
|
206
|
+
2. Sync.ListRow
|
207
|
+
3. Sync.View (Default fallback)
|
208
|
+
|
209
|
+
|
210
|
+
For example, if you wanted to fade in/out a row in a sync'd todo list instead of the Sync.View default of instant insert/remove:
|
211
|
+
|
212
|
+
```coffeescript
|
213
|
+
class Sync.TodoListRow extends Sync.View
|
214
|
+
|
215
|
+
beforeInsert: ($el) ->
|
216
|
+
$el.hide()
|
217
|
+
@insert($el)
|
218
|
+
|
219
|
+
afterInsert: -> @$el.fadeIn 'slow'
|
220
|
+
|
221
|
+
beforeRemove: -> @$el.fadeOut 'slow', => @remove()
|
222
|
+
|
223
|
+
```
|
224
|
+
|
225
|
+
## Narrowing sync_new scope
|
226
|
+
|
227
|
+
Sometimes, you do not want your page to update with every new record. With the `scope` option, you can limit what is being updated on a given page.
|
228
|
+
|
229
|
+
One way of using `scope` is by supplying a String or a Symbol. This is useful for example when you want to only show new records for a given locale:
|
230
|
+
|
231
|
+
View:
|
232
|
+
```erb
|
233
|
+
<%= sync_new partial: 'todo_list_row', resource: Todo.new, scope: I18n.locale %>
|
234
|
+
```
|
235
|
+
|
236
|
+
Controller/Model:
|
237
|
+
```ruby
|
238
|
+
sync_new @todo, scope: @todo.locale
|
239
|
+
```
|
240
|
+
|
241
|
+
Another use of `scope` is with a parent resource. This way you can for example update a project page with new todos for this single project:
|
242
|
+
|
243
|
+
View:
|
244
|
+
```erb
|
245
|
+
<%= sync_new partial: 'todo_list_row', resource: Todo.new, scope: @project %>
|
246
|
+
```
|
247
|
+
|
248
|
+
Controller/Model:
|
249
|
+
```ruby
|
250
|
+
sync_new @todo, scope: @project
|
251
|
+
```
|
252
|
+
|
253
|
+
Both approaches can be combined. Just supply an Array of Strings/Symbols and/or parent resources to the `scope` option. Note that the order of elements matters. Be sure to use the same order in your view and in your controller/model.
|
254
|
+
|
255
|
+
## Refetching Partials
|
256
|
+
|
257
|
+
Refetching allows syncing partials across different users when the partial requires the session's context (ie. current_user).
|
258
|
+
|
259
|
+
Ex:
|
260
|
+
View: Add `refetch: true` to sync calls, and place partial file in a 'refetch'
|
261
|
+
subdirectory in the model's sync view folder:
|
262
|
+
|
263
|
+
The partial file would be located in `app/views/sync/todos/refetch/_list_row.html.erb`
|
264
|
+
```erb
|
265
|
+
<% @project.todos.ordered.each do |todo| %>
|
266
|
+
<%= sync partial: 'list_row', resource: todo, refetch: true %>
|
267
|
+
<% end %>
|
268
|
+
<%= sync_new partial: 'list_row', resource: Todo.new, scope: @project, refetch: true %>
|
269
|
+
```
|
270
|
+
|
271
|
+
*Notes*
|
272
|
+
|
273
|
+
While this approach works very well for the cases it's needed, syncing without refetching should be used unless refetching is absolutely necessary for performance reasons. For example,
|
274
|
+
|
275
|
+
A sync update request is triggered on the server for a 'regular' sync'd partial with 100 listening clients:
|
276
|
+
- number of http requests 1
|
277
|
+
- number of renders 1, pushed out to all 100 clients via pubsub server.
|
278
|
+
|
279
|
+
|
280
|
+
A sync update request is triggered on the server for a 'refetch' sync'd partial with 100 listening clients:
|
281
|
+
- number of http requests 100
|
282
|
+
- number of renders 100, rendering each request in clients session context.
|
283
|
+
|
284
|
+
## Using with cache_digests (Russian doll caching)
|
285
|
+
|
286
|
+
Sync has a custom `DependencyTracker::ERBTracker` that can handle `sync` render calls.
|
287
|
+
Because the full partial name is not included, it has to guess the location of
|
288
|
+
your partial based on the name of the `resource` or `collection` passed to it.
|
289
|
+
See the tests to see how it works. If it doesn't work for you, you can always
|
290
|
+
use the [explicit "Template Dependency"
|
291
|
+
markers](https://github.com/rails/cache_digests).
|
292
|
+
|
293
|
+
To enable, add to `config/initializers/cache_digests.rb`:
|
294
|
+
|
295
|
+
#### Rails 4
|
296
|
+
|
297
|
+
```ruby
|
298
|
+
require 'action_view/dependency_tracker'
|
299
|
+
|
300
|
+
ActionView::DependencyTracker.register_tracker :haml, Sync::ERBTracker
|
301
|
+
ActionView::DependencyTracker.register_tracker :erb, Sync::ERBTracker
|
302
|
+
```
|
303
|
+
|
304
|
+
#### Rails 3 with [cache_digests](https://github.com/rails/cache_digests) gem
|
305
|
+
|
306
|
+
```ruby
|
307
|
+
require 'cache_digests/dependency_tracker'
|
308
|
+
|
309
|
+
CacheDigests::DependencyTracker.register_tracker :haml, Sync::ERBTracker
|
310
|
+
CacheDigests::DependencyTracker.register_tracker :erb, Sync::ERBTracker
|
311
|
+
```
|
312
|
+
|
313
|
+
**Note:** haml support is limited, but it seems to work in most cases.
|
314
|
+
|
315
|
+
|
316
|
+
## Serving Faye over HTTPS (with Thin)
|
317
|
+
|
318
|
+
Create a thin configuration file `config/sync_thin.yml` similar to the following:
|
319
|
+
|
320
|
+
```yaml
|
321
|
+
---
|
322
|
+
port: 4443
|
323
|
+
ssl: true
|
324
|
+
ssl_key_file: /path/to/server.pem
|
325
|
+
ssl_cert_file: /path/to/certificate_chain.pem
|
326
|
+
environment: production
|
327
|
+
rackup: sync.ru
|
328
|
+
```
|
329
|
+
|
330
|
+
The `certificate_chain.pem` file should contain your signed certificate, followed by intermediate certificates (if any) and the root certificate of the CA that signed the key.
|
331
|
+
|
332
|
+
Next reconfigure the `server` and `adapter_javascript_url` in `config/sync.yml` to look like `https://your.hostname.com:4443/faye` and `https://your.hostname.com:4443/faye/faye.js` respectively.
|
333
|
+
|
334
|
+
Finally start up Thin from the project root.
|
335
|
+
|
336
|
+
```
|
337
|
+
thin -C config/sync_thin.yml start
|
338
|
+
```
|
339
|
+
|
340
|
+
|
341
|
+
## Brief Example or [checkout an example application](https://github.com/chrismccord/sync_example)
|
342
|
+
|
343
|
+
View `sync/users/_user_list_row.html.erb`
|
344
|
+
|
345
|
+
```erb
|
346
|
+
<tr>
|
347
|
+
<td><%= link_to user.name, user %></td>
|
348
|
+
<td><%= link_to 'Edit', edit_user_path(user) %></td>
|
349
|
+
<td><%= link_to 'Destroy', user, method: :delete, remote: true, data: { confirm: 'Are you sure?' } %></td>
|
350
|
+
</tr>
|
351
|
+
```
|
352
|
+
|
353
|
+
View `users/index.html.erb`
|
354
|
+
|
355
|
+
```erb
|
356
|
+
<h1>Some Users</h1>
|
357
|
+
<table>
|
358
|
+
<tbody>
|
359
|
+
<%= sync partial: 'user_list_row', collection: @users %>
|
360
|
+
<%= sync_new partial: 'user_list_row', resource: User.new, direction: :append %>
|
361
|
+
</tbody>
|
362
|
+
</table>
|
363
|
+
```
|
364
|
+
|
365
|
+
|
366
|
+
Controller
|
367
|
+
|
368
|
+
```ruby
|
369
|
+
def UsersController < ApplicationController
|
370
|
+
…
|
371
|
+
def create
|
372
|
+
@user = User.new(user_params)
|
373
|
+
if @user.save
|
374
|
+
sync_new @user
|
375
|
+
end
|
376
|
+
respond_to do |format|
|
377
|
+
format.html { redirect_to users_url }
|
378
|
+
format.json { head :no_content }
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
def update
|
383
|
+
@user = User.find(params[:id])
|
384
|
+
if user.save
|
385
|
+
…
|
386
|
+
end
|
387
|
+
|
388
|
+
# Sync updates to any partials listening for this user
|
389
|
+
sync_update @user
|
390
|
+
|
391
|
+
redirect_to users_path, notice: "Saved!"
|
392
|
+
end
|
393
|
+
|
394
|
+
def destroy
|
395
|
+
@user = User.find(params[:id])
|
396
|
+
@user.destroy
|
397
|
+
|
398
|
+
# Sync destroy, telling client to remove all dom elements containing this user
|
399
|
+
sync_destroy @user
|
400
|
+
|
401
|
+
respond_to do |format|
|
402
|
+
format.html { redirect_to users_url }
|
403
|
+
format.json { head :no_content }
|
404
|
+
end
|
405
|
+
end
|
406
|
+
end
|
407
|
+
```
|
408
|
+
|
data/Rakefile
ADDED
File without changes
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module SyncBumper
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
def self.source_root
|
5
|
+
File.dirname(__FILE__) + "/templates"
|
6
|
+
end
|
7
|
+
|
8
|
+
def copy_files
|
9
|
+
template "sync_bumper.rb", "config/initializers/sync_bumper.rb"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
SyncBumper.configure do |c|
|
2
|
+
c.url = case
|
3
|
+
when Rails.env.production?
|
4
|
+
lambda { |id| "http://example.com/todos/#{id}/bumper" }
|
5
|
+
when Rails.env.development?
|
6
|
+
lambda { |id| "http://example.com/todos/#{id}/bumper" }
|
7
|
+
else
|
8
|
+
lambda { |id| "http://example.com/todos/#{id}/bumper" }
|
9
|
+
end
|
10
|
+
end
|
data/lib/sync_bumper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
require 'digest/sha1'
|
3
|
+
require 'net/http'
|
4
|
+
require 'net/https'
|
5
|
+
|
6
|
+
require 'sync_bumper/model'
|
7
|
+
|
8
|
+
module SyncBumper
|
9
|
+
|
10
|
+
class << self
|
11
|
+
attr_accessor :url
|
12
|
+
|
13
|
+
def configure(&blk); class_eval(&blk); end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
if defined? Rails
|
20
|
+
# path = Rails.root.join("config/sync_bumper.yml")
|
21
|
+
# SyncBumper.load_config(path, Rails.env) if path.exist?
|
22
|
+
|
23
|
+
ActiveRecord::Base.send :extend, SyncBumper::Model::ClassMethods
|
24
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module SyncBumper
|
2
|
+
module Model
|
3
|
+
|
4
|
+
def self.enabled?
|
5
|
+
Thread.current["model_sync_enabled"]
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.context
|
9
|
+
Thread.current["model_sync_context"]
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.enable!(context = nil)
|
13
|
+
Thread.current["model_sync_enabled"] = true
|
14
|
+
Thread.current["model_sync_context"] = context
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.disable!
|
18
|
+
Thread.current["model_sync_enabled"] = false
|
19
|
+
Thread.current["model_sync_context"] = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.enable(context = nil)
|
23
|
+
enable!(context)
|
24
|
+
yield
|
25
|
+
ensure
|
26
|
+
disable!
|
27
|
+
end
|
28
|
+
|
29
|
+
module ClassMethods
|
30
|
+
attr_accessor :sync_scope
|
31
|
+
|
32
|
+
def sync(*actions)
|
33
|
+
include ModelActions
|
34
|
+
if actions.last.is_a? Hash
|
35
|
+
@sync_scope = actions.last.fetch :scope
|
36
|
+
end
|
37
|
+
actions = [:create, :update, :destroy] if actions.include? :all
|
38
|
+
actions.flatten!
|
39
|
+
|
40
|
+
if actions.include? :create
|
41
|
+
after_create :publish_sync_create, :on => :create#, :if => lamda { Sync::Model.enabled? }
|
42
|
+
end
|
43
|
+
if actions.include? :update
|
44
|
+
after_update :publish_sync_update, :on => :update#, :if => lamda { Sync::Model.enabled? }
|
45
|
+
end
|
46
|
+
if actions.include? :destroy
|
47
|
+
after_destroy :publish_sync_destroy, :on => :destroy#, :if => lamda { Sync::Model.enabled? }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
module ModelActions
|
53
|
+
def sync_scope
|
54
|
+
return nil unless self.class.sync_scope
|
55
|
+
send self.class.sync_scope
|
56
|
+
end
|
57
|
+
|
58
|
+
def publish_sync_create
|
59
|
+
Thread.new do
|
60
|
+
uri = URI(SyncBumper.url.call(id))
|
61
|
+
req = Net::HTTP::Post.new(uri.request_uri)
|
62
|
+
|
63
|
+
perform_request(req, uri)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def publish_sync_update
|
68
|
+
Thread.new do
|
69
|
+
uri = URI(SyncBumper.url.call(id))
|
70
|
+
req = Net::HTTP::Put.new(uri.request_uri)
|
71
|
+
|
72
|
+
perform_request(req, uri)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def publish_sync_destroy
|
77
|
+
Thread.new do
|
78
|
+
uri = URI(SyncBumper.url.call(id))
|
79
|
+
req = Net::HTTP::Delete.new(uri.request_uri)
|
80
|
+
|
81
|
+
perform_request(req, uri)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def perform_request(req, uri)
|
86
|
+
req["Content-Type"] = 'text/plain;charset=UTF-8'
|
87
|
+
req["Content-Length"] = '0'
|
88
|
+
|
89
|
+
res = Net::HTTP.start(uri.host, uri.port) { |http| http.request(req) }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sync_bumper
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alexey Dubovskoy
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: em-http-request
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rails
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.3.18
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 2.3.18
|
41
|
+
description: Bumper to involve Sync callbacks at external Rails App. Sync turns your
|
42
|
+
Rails partials realtime with automatic updates through Faye
|
43
|
+
email: dubovskoy.a@gmail.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- lib/generators/sync/install_generator.rb
|
49
|
+
- lib/generators/sync/templates/sync_bumper.rb
|
50
|
+
- lib/sync_bumper/model.rb
|
51
|
+
- lib/sync_bumper.rb
|
52
|
+
- CHANGELOG.md
|
53
|
+
- Gemfile
|
54
|
+
- LICENSE
|
55
|
+
- Rakefile
|
56
|
+
- README.md
|
57
|
+
homepage: http://github.com/dubadub/sync_bumper
|
58
|
+
licenses: []
|
59
|
+
metadata: {}
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options: []
|
62
|
+
require_paths:
|
63
|
+
- lib
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 1.3.4
|
74
|
+
requirements: []
|
75
|
+
rubyforge_project:
|
76
|
+
rubygems_version: 2.0.14
|
77
|
+
signing_key:
|
78
|
+
specification_version: 4
|
79
|
+
summary: Bumper to involve Sync callbacks at external Rails App
|
80
|
+
test_files: []
|