dexiecable 0.1.6 → 0.1.7
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 +19 -17
- data/lib/dexiecable/active_record_ext.rb +24 -24
- data/lib/dexiecable/concern.rb +3 -3
- data/lib/dexiecable/scoped_channel.rb +4 -4
- data/lib/dexiecable/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 85944f789c9d0a2a10d718fbab783e4c9b89e00bb2ad0fe2cb5804648660447c
|
|
4
|
+
data.tar.gz: a17bc5ccd07702c90ea508b9261391980fbfa68e4bf1a5d1b9dc4f85f6a8c417
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 62b8fbad4ae8392ec0da800697247833a62cdd1dd8165f95ed05c6b81e4b97a4984e75eb3179481139e9bf8f2378641eecb50e2e7ba5503c94f445a9e30e7128
|
|
7
|
+
data.tar.gz: 17330cb1f871afb2b9599596e2d8f1cd882fe323c686f9464490b779e1f2fdfbb4c9b6a9bacca0bd2eb5751ff4001a93cea4f0cbb9dbacae4ab1a1d6489ac2a0
|
data/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Run [Dexie.js](https://dexie.org) IndexedDB operations from your Rails ActionCable channels.
|
|
4
4
|
|
|
5
|
-
DexieCable augments ActionCable channels with a query DSL that mirrors the Dexie.js API, letting you push database mutations from the server to the client in real time. It also gives you a `syncs_to_dexie` ActiveRecord macro for automatic change syncing.
|
|
5
|
+
DexieCable augments ActionCable channels with a query DSL that mirrors the Dexie.js API, letting you push database mutations from the server to the client in real time. It also gives you a [`syncs_to_dexie`](#syncs_to_dexie--automatic-model-syncing) ActiveRecord macro for automatic change syncing.
|
|
6
6
|
|
|
7
7
|
You can run any Dexie table update directly inside a channel:
|
|
8
8
|
|
|
@@ -29,11 +29,11 @@ class NotificationsController < ApplicationController
|
|
|
29
29
|
end
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
An even more convenient way is to use the `syncs_to_dexie` macro
|
|
32
|
+
An even more convenient way is to use the `syncs_to_dexie` macro (more info [below](#syncs_to_dexie--automatic-model-syncing))
|
|
33
33
|
|
|
34
34
|
```ruby
|
|
35
35
|
class Notification < ApplicationRecord
|
|
36
|
-
syncs_to_dexie via: UserChannel,
|
|
36
|
+
syncs_to_dexie via: UserChannel, to: :user
|
|
37
37
|
end
|
|
38
38
|
```
|
|
39
39
|
|
|
@@ -89,7 +89,7 @@ This gives you:
|
|
|
89
89
|
|
|
90
90
|
| Method | Description |
|
|
91
91
|
|---|---|
|
|
92
|
-
| `self.[](
|
|
92
|
+
| `self.[](to)` | Returns a `ScopedChannel` bound to a recipient. `UserChannel[current_user]` |
|
|
93
93
|
| `table(name)` | Starts a query chain. `table("messages")` |
|
|
94
94
|
|
|
95
95
|
### Chaining Dexie operations
|
|
@@ -125,34 +125,36 @@ The full query chain is serialized as JSON and sent over ActionCable. The JS cli
|
|
|
125
125
|
|
|
126
126
|
### `syncs_to_dexie` — automatic model syncing
|
|
127
127
|
|
|
128
|
-
Add to any ActiveRecord model.
|
|
128
|
+
Add to any ActiveRecord model. Just provide the channel class and the broadcast target.
|
|
129
129
|
|
|
130
130
|
```ruby
|
|
131
131
|
class Message < ApplicationRecord
|
|
132
|
-
# Calls send(:receiver), then broadcasts: broadcast_to(receiver, ...)
|
|
133
|
-
syncs_to_dexie via: UserChannel,
|
|
132
|
+
# Calls send(:receiver), then broadcasts: UserChannel.broadcast_to(receiver, ...)
|
|
133
|
+
syncs_to_dexie via: UserChannel, to: :receiver
|
|
134
134
|
|
|
135
|
-
# String used directly: broadcast_to("global_feed", ...)
|
|
136
|
-
syncs_to_dexie via: UserChannel,
|
|
135
|
+
# String used directly: UserChannel.broadcast_to("global_feed", ...)
|
|
136
|
+
syncs_to_dexie via: UserChannel, to: "global_feed"
|
|
137
137
|
|
|
138
138
|
# Procs are also supported. If an array is returned, multiple broadcasts are made
|
|
139
|
-
# conversation.users.each { |u| broadcast_to(u, ...) }
|
|
140
|
-
syncs_to_dexie via: UserChannel,
|
|
139
|
+
# conversation.users.each { |u| UserChannel.broadcast_to(u, ...) }
|
|
140
|
+
syncs_to_dexie via: UserChannel, to: -> { conversation.users }
|
|
141
141
|
end
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
+
Internally, `syncs_to_dexie` sets up the following ActiveRecord callbacks:
|
|
145
|
+
|
|
144
146
|
| Event | Action |
|
|
145
147
|
|---|---|
|
|
146
|
-
| `after_commit on: :create` | `channel.table(
|
|
147
|
-
| `after_commit on: :update` | `channel.table(
|
|
148
|
-
| `after_commit on: :destroy` | `channel.table(
|
|
148
|
+
| `after_commit on: :create` | `channel.table(table).add(record.as_json_for_dexie)` |
|
|
149
|
+
| `after_commit on: :update` | `channel.table(table).put(record.as_json_for_dexie)` |
|
|
150
|
+
| `after_commit on: :destroy` | `channel.table(table).delete(record.id)` |
|
|
149
151
|
|
|
150
152
|
#### Options
|
|
151
153
|
|
|
152
154
|
| Option | Default | Description |
|
|
153
155
|
|---|---|---|
|
|
154
156
|
| `via:` | *(required)* | A DexieCable channel class |
|
|
155
|
-
| `
|
|
157
|
+
| `to:` | *(none)* | The stream target passed to `broadcast_to`. Symbol → calls `send`. String → used as-is. Proc → evaluated in record context. Returns a single recipient or collection. |
|
|
156
158
|
| `table:` | model's `table_name` | Override the Dexie table name. A Proc is evaluated in the record's context. |
|
|
157
159
|
| `only:` | `[:create, :update, :destroy]` | Limit which events trigger a sync |
|
|
158
160
|
| `if:` | *(none)* | Symbol (method name) or Proc — only sync when it returns truthy |
|
|
@@ -162,7 +164,7 @@ You can combine multiple `syncs_to_dexie` declarations, each with different cond
|
|
|
162
164
|
|
|
163
165
|
```ruby
|
|
164
166
|
class Message < ApplicationRecord
|
|
165
|
-
syncs_to_dexie via: UserChannel,
|
|
167
|
+
syncs_to_dexie via: UserChannel, to: -> { sender },
|
|
166
168
|
if: :published?
|
|
167
169
|
|
|
168
170
|
syncs_to_dexie via: AdminChannel,
|
|
@@ -176,7 +178,7 @@ Override `as_json_for_dexie` in your model:
|
|
|
176
178
|
|
|
177
179
|
```ruby
|
|
178
180
|
class Message < ApplicationRecord
|
|
179
|
-
syncs_to_dexie via: UserChannel,
|
|
181
|
+
syncs_to_dexie via: UserChannel, to: :sender
|
|
180
182
|
|
|
181
183
|
def as_json_for_dexie
|
|
182
184
|
super.merge(room_name: room.name)
|
|
@@ -9,22 +9,22 @@ module DexieCable
|
|
|
9
9
|
# DexieCable channel.
|
|
10
10
|
#
|
|
11
11
|
# class Message < ApplicationRecord
|
|
12
|
-
# syncs_to_dexie via: UserChannel,
|
|
13
|
-
# syncs_to_dexie via: UserChannel,
|
|
14
|
-
# syncs_to_dexie via: UserChannel,
|
|
12
|
+
# syncs_to_dexie via: UserChannel, to: :sender
|
|
13
|
+
# syncs_to_dexie via: UserChannel, to: "global_feed"
|
|
14
|
+
# syncs_to_dexie via: UserChannel, to: -> { conversation.users }
|
|
15
15
|
# syncs_to_dexie via: PublicChannel
|
|
16
16
|
# end
|
|
17
17
|
#
|
|
18
|
-
# @param via [Class] A DexieCable channel class. When +
|
|
19
|
-
# is given, each
|
|
20
|
-
# +via[
|
|
21
|
-
# Without +
|
|
18
|
+
# @param via [Class] A DexieCable channel class. When +to+
|
|
19
|
+
# is given, each recipient is mapped through
|
|
20
|
+
# +via[to]+ to produce scoped channels.
|
|
21
|
+
# Without +to+, +via+ is used directly as an
|
|
22
22
|
# unscoped channel.
|
|
23
|
-
# @param
|
|
23
|
+
# @param to [Proc, Symbol, String] A Proc evaluated in record
|
|
24
24
|
# context, a Symbol to call via +send+, or a String
|
|
25
25
|
# used directly as the stream name for +broadcast_to+.
|
|
26
|
-
# Must return a single
|
|
27
|
-
#
|
|
26
|
+
# Must return a single recipient or collection of
|
|
27
|
+
# recipients.
|
|
28
28
|
# @param table [String, Symbol, Proc] Override the Dexie table name
|
|
29
29
|
# (defaults to the model's table_name). A Proc is
|
|
30
30
|
# evaluated in the record's context.
|
|
@@ -34,18 +34,18 @@ module DexieCable
|
|
|
34
34
|
# returns truthy (evaluated in the record's context).
|
|
35
35
|
# @param unless [Symbol, Proc] Skip sync if the given method or proc
|
|
36
36
|
# returns truthy (evaluated in the record's context).
|
|
37
|
-
def syncs_to_dexie(via:,
|
|
37
|
+
def syncs_to_dexie(via:, to: nil, table: nil, only: nil, **options)
|
|
38
38
|
events = Array(only || %i[create update destroy])
|
|
39
39
|
conditions = options.slice(:if, :unless)
|
|
40
40
|
|
|
41
41
|
@dexie_sync_configs ||= []
|
|
42
|
-
@dexie_sync_configs << { via: via,
|
|
42
|
+
@dexie_sync_configs << { via: via, to: to, table: table, only: events, **conditions }
|
|
43
43
|
|
|
44
44
|
if events.include?(:destroy)
|
|
45
45
|
before_destroy :dexie_sync_before_destroy
|
|
46
46
|
|
|
47
47
|
after_commit on: :destroy, **conditions do
|
|
48
|
-
Array(resolve_channel(via,
|
|
48
|
+
Array(resolve_channel(via, to)).each do |channel|
|
|
49
49
|
next unless channel
|
|
50
50
|
channel.table(resolve_table(table)).delete(dexie_destroy_id)
|
|
51
51
|
end
|
|
@@ -54,7 +54,7 @@ module DexieCable
|
|
|
54
54
|
|
|
55
55
|
if events.include?(:create)
|
|
56
56
|
after_commit on: :create, **conditions do
|
|
57
|
-
Array(resolve_channel(via,
|
|
57
|
+
Array(resolve_channel(via, to)).each do |channel|
|
|
58
58
|
next unless channel
|
|
59
59
|
channel.table(resolve_table(table)).add(as_json_for_dexie)
|
|
60
60
|
end
|
|
@@ -63,7 +63,7 @@ module DexieCable
|
|
|
63
63
|
|
|
64
64
|
if events.include?(:update)
|
|
65
65
|
after_commit on: :update, **conditions do
|
|
66
|
-
Array(resolve_channel(via,
|
|
66
|
+
Array(resolve_channel(via, to)).each do |channel|
|
|
67
67
|
next unless channel
|
|
68
68
|
|
|
69
69
|
changes = as_json_for_dexie.slice(*saved_changes.keys)
|
|
@@ -76,20 +76,20 @@ module DexieCable
|
|
|
76
76
|
|
|
77
77
|
private
|
|
78
78
|
|
|
79
|
-
def resolve_channel(via,
|
|
80
|
-
if
|
|
81
|
-
|
|
82
|
-
Array(
|
|
79
|
+
def resolve_channel(via, to = nil)
|
|
80
|
+
if to
|
|
81
|
+
recipients = resolve_recipient(to)
|
|
82
|
+
Array(recipients).map { |r| via[r] }
|
|
83
83
|
else
|
|
84
84
|
via
|
|
85
85
|
end
|
|
86
86
|
end
|
|
87
87
|
|
|
88
|
-
def
|
|
89
|
-
case
|
|
90
|
-
when Proc then instance_exec(&
|
|
91
|
-
when Symbol then send(
|
|
92
|
-
else
|
|
88
|
+
def resolve_recipient(to)
|
|
89
|
+
case to
|
|
90
|
+
when Proc then instance_exec(&to)
|
|
91
|
+
when Symbol then send(to)
|
|
92
|
+
else to
|
|
93
93
|
end
|
|
94
94
|
end
|
|
95
95
|
|
data/lib/dexiecable/concern.rb
CHANGED
|
@@ -6,12 +6,12 @@ module DexieCable
|
|
|
6
6
|
included do
|
|
7
7
|
public :transmit
|
|
8
8
|
|
|
9
|
-
# Open a scoped channel for broadcasting to a specific
|
|
9
|
+
# Open a scoped channel for broadcasting to a specific recipient.
|
|
10
10
|
#
|
|
11
11
|
# UserChannel[current_user].table("notifications").add(notification)
|
|
12
12
|
#
|
|
13
|
-
def self.[](
|
|
14
|
-
ScopedChannel.new(self,
|
|
13
|
+
def self.[](recipient)
|
|
14
|
+
ScopedChannel.new(self, recipient)
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
# Build a query against a Dexie table, transmitted to all subscribers
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
module DexieCable
|
|
4
4
|
class ScopedChannel
|
|
5
|
-
def initialize(klass,
|
|
6
|
-
@klass
|
|
7
|
-
@
|
|
5
|
+
def initialize(klass, recipient)
|
|
6
|
+
@klass = klass
|
|
7
|
+
@recipient = recipient
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def table(name)
|
|
@@ -12,7 +12,7 @@ module DexieCable
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def transmit(data)
|
|
15
|
-
@klass.broadcast_to @
|
|
15
|
+
@klass.broadcast_to @recipient, data
|
|
16
16
|
end
|
|
17
17
|
end
|
|
18
18
|
end
|
data/lib/dexiecable/version.rb
CHANGED