model_transporter 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0f85c3aa56fedb4237493e78e6abfe03e88f9ecbc8907dcc714ffe5d436285b1
4
+ data.tar.gz: 11eb1c754d336dd7f535cbcf188b1d7c73e3b94d4cd6a1ccb5db7770134c07c4
5
+ SHA512:
6
+ metadata.gz: 485810e34216ea08baab535190b57f5dc0a61767f9543da1be9bd4c2dcd5b7825f49a4fe21658be024c2d4ff2a35b78f0ef9a961855987e32ddf9870011298cf
7
+ data.tar.gz: 492322272edcfc870a0d29614188b5d745434e8e50f88357ce7b73d5e0d1c82b12eafab20941ca110ee630d47bdfa2cb8096e2c2d8708e9c761d6e4a296ea36a
@@ -0,0 +1,18 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+ spec/test_app/node_modules/
13
+ spec/test_app/tmp/
14
+ spec/test_app/db/development.sqlite3
15
+ spec/test_app/log/development.log
16
+ tags
17
+ spec/test_app/db/test.sqlite3
18
+ spec/test_app/log/test.log
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1 @@
1
+ 2.7.1
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.5.3
7
+ before_install: gem install bundler -v 2.0.2
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ ruby '2.7.1'
4
+
5
+ # Specify your gem's dependencies in model_transporter.gemspec
6
+ gemspec
@@ -0,0 +1,207 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ model_transporter (0.1.0)
5
+ rails (~> 6.0)
6
+ request_store
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ actioncable (6.0.3.4)
12
+ actionpack (= 6.0.3.4)
13
+ nio4r (~> 2.0)
14
+ websocket-driver (>= 0.6.1)
15
+ actionmailbox (6.0.3.4)
16
+ actionpack (= 6.0.3.4)
17
+ activejob (= 6.0.3.4)
18
+ activerecord (= 6.0.3.4)
19
+ activestorage (= 6.0.3.4)
20
+ activesupport (= 6.0.3.4)
21
+ mail (>= 2.7.1)
22
+ actionmailer (6.0.3.4)
23
+ actionpack (= 6.0.3.4)
24
+ actionview (= 6.0.3.4)
25
+ activejob (= 6.0.3.4)
26
+ mail (~> 2.5, >= 2.5.4)
27
+ rails-dom-testing (~> 2.0)
28
+ actionpack (6.0.3.4)
29
+ actionview (= 6.0.3.4)
30
+ activesupport (= 6.0.3.4)
31
+ rack (~> 2.0, >= 2.0.8)
32
+ rack-test (>= 0.6.3)
33
+ rails-dom-testing (~> 2.0)
34
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
35
+ actiontext (6.0.3.4)
36
+ actionpack (= 6.0.3.4)
37
+ activerecord (= 6.0.3.4)
38
+ activestorage (= 6.0.3.4)
39
+ activesupport (= 6.0.3.4)
40
+ nokogiri (>= 1.8.5)
41
+ actionview (6.0.3.4)
42
+ activesupport (= 6.0.3.4)
43
+ builder (~> 3.1)
44
+ erubi (~> 1.4)
45
+ rails-dom-testing (~> 2.0)
46
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
47
+ activejob (6.0.3.4)
48
+ activesupport (= 6.0.3.4)
49
+ globalid (>= 0.3.6)
50
+ activemodel (6.0.3.4)
51
+ activesupport (= 6.0.3.4)
52
+ activerecord (6.0.3.4)
53
+ activemodel (= 6.0.3.4)
54
+ activesupport (= 6.0.3.4)
55
+ activestorage (6.0.3.4)
56
+ actionpack (= 6.0.3.4)
57
+ activejob (= 6.0.3.4)
58
+ activerecord (= 6.0.3.4)
59
+ marcel (~> 0.3.1)
60
+ activesupport (6.0.3.4)
61
+ concurrent-ruby (~> 1.0, >= 1.0.2)
62
+ i18n (>= 0.7, < 2)
63
+ minitest (~> 5.1)
64
+ tzinfo (~> 1.1)
65
+ zeitwerk (~> 2.2, >= 2.2.2)
66
+ builder (3.2.4)
67
+ coderay (1.1.3)
68
+ concurrent-ruby (1.1.7)
69
+ crass (1.0.6)
70
+ diff-lcs (1.4.4)
71
+ erubi (1.9.0)
72
+ ffi (1.13.1)
73
+ globalid (0.4.2)
74
+ activesupport (>= 4.2.0)
75
+ i18n (1.8.5)
76
+ concurrent-ruby (~> 1.0)
77
+ listen (3.2.1)
78
+ rb-fsevent (~> 0.10, >= 0.10.3)
79
+ rb-inotify (~> 0.9, >= 0.9.10)
80
+ loofah (2.7.0)
81
+ crass (~> 1.0.2)
82
+ nokogiri (>= 1.5.9)
83
+ mail (2.7.1)
84
+ mini_mime (>= 0.1.1)
85
+ marcel (0.3.3)
86
+ mimemagic (~> 0.3.2)
87
+ method_source (1.0.0)
88
+ mimemagic (0.3.5)
89
+ mini_mime (1.0.2)
90
+ mini_portile2 (2.4.0)
91
+ minitest (5.14.2)
92
+ nio4r (2.5.4)
93
+ nokogiri (1.10.10)
94
+ mini_portile2 (~> 2.4.0)
95
+ pry (0.13.1)
96
+ coderay (~> 1.1)
97
+ method_source (~> 1.0)
98
+ rack (2.2.3)
99
+ rack-proxy (0.6.5)
100
+ rack
101
+ rack-test (1.1.0)
102
+ rack (>= 1.0, < 3)
103
+ rails (6.0.3.4)
104
+ actioncable (= 6.0.3.4)
105
+ actionmailbox (= 6.0.3.4)
106
+ actionmailer (= 6.0.3.4)
107
+ actionpack (= 6.0.3.4)
108
+ actiontext (= 6.0.3.4)
109
+ actionview (= 6.0.3.4)
110
+ activejob (= 6.0.3.4)
111
+ activemodel (= 6.0.3.4)
112
+ activerecord (= 6.0.3.4)
113
+ activestorage (= 6.0.3.4)
114
+ activesupport (= 6.0.3.4)
115
+ bundler (>= 1.3.0)
116
+ railties (= 6.0.3.4)
117
+ sprockets-rails (>= 2.0.0)
118
+ rails-dom-testing (2.0.3)
119
+ activesupport (>= 4.2.0)
120
+ nokogiri (>= 1.6)
121
+ rails-html-sanitizer (1.3.0)
122
+ loofah (~> 2.3)
123
+ railties (6.0.3.4)
124
+ actionpack (= 6.0.3.4)
125
+ activesupport (= 6.0.3.4)
126
+ method_source
127
+ rake (>= 0.8.7)
128
+ thor (>= 0.20.3, < 2.0)
129
+ rake (13.0.1)
130
+ rb-fsevent (0.10.4)
131
+ rb-inotify (0.10.1)
132
+ ffi (~> 1.0)
133
+ request_store (1.5.0)
134
+ rack (>= 1.4)
135
+ rspec (3.9.0)
136
+ rspec-core (~> 3.9.0)
137
+ rspec-expectations (~> 3.9.0)
138
+ rspec-mocks (~> 3.9.0)
139
+ rspec-core (3.9.3)
140
+ rspec-support (~> 3.9.3)
141
+ rspec-expectations (3.9.2)
142
+ diff-lcs (>= 1.2.0, < 2.0)
143
+ rspec-support (~> 3.9.0)
144
+ rspec-mocks (3.9.1)
145
+ diff-lcs (>= 1.2.0, < 2.0)
146
+ rspec-support (~> 3.9.0)
147
+ rspec-rails (4.0.1)
148
+ actionpack (>= 4.2)
149
+ activesupport (>= 4.2)
150
+ railties (>= 4.2)
151
+ rspec-core (~> 3.9)
152
+ rspec-expectations (~> 3.9)
153
+ rspec-mocks (~> 3.9)
154
+ rspec-support (~> 3.9)
155
+ rspec-support (3.9.3)
156
+ sass-rails (6.0.0)
157
+ sassc-rails (~> 2.1, >= 2.1.1)
158
+ sassc (2.4.0)
159
+ ffi (~> 1.9)
160
+ sassc-rails (2.1.2)
161
+ railties (>= 4.0.0)
162
+ sassc (>= 2.0)
163
+ sprockets (> 3.0)
164
+ sprockets-rails
165
+ tilt
166
+ sprockets (4.0.2)
167
+ concurrent-ruby (~> 1.0)
168
+ rack (> 1, < 3)
169
+ sprockets-rails (3.2.2)
170
+ actionpack (>= 4.0)
171
+ activesupport (>= 4.0)
172
+ sprockets (>= 3.0.0)
173
+ sqlite3 (1.4.2)
174
+ thor (1.0.1)
175
+ thread_safe (0.3.6)
176
+ tilt (2.0.10)
177
+ tzinfo (1.2.7)
178
+ thread_safe (~> 0.1)
179
+ webpacker (4.3.0)
180
+ activesupport (>= 4.2)
181
+ rack-proxy (>= 0.6.1)
182
+ railties (>= 4.2)
183
+ websocket-driver (0.7.3)
184
+ websocket-extensions (>= 0.1.0)
185
+ websocket-extensions (0.1.5)
186
+ zeitwerk (2.4.0)
187
+
188
+ PLATFORMS
189
+ ruby
190
+
191
+ DEPENDENCIES
192
+ bundler (~> 2.0)
193
+ listen
194
+ model_transporter!
195
+ pry
196
+ rake (~> 13.0)
197
+ rspec (~> 3.0)
198
+ rspec-rails
199
+ sass-rails (>= 6)
200
+ sqlite3 (~> 1.4)
201
+ webpacker (~> 4.0)
202
+
203
+ RUBY VERSION
204
+ ruby 2.7.1p83
205
+
206
+ BUNDLED WITH
207
+ 2.1.4
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Andrew Warner
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,126 @@
1
+ # ModelTransporter
2
+
3
+ Syndicate Rails model updates to your client-side Redux store via Action Cable.
4
+
5
+ If you have many users viewing the same objects in different sessions, stored in Redux or a similar client-side store, `ModelTransporter` allows updates made by one client to flow to the others instantly. Since clients typically update models via web requests, `ModelTransporter` batches updates from each request together so that listeners see changes to all related objects at once.
6
+
7
+ ![](https://user-images.githubusercontent.com/952319/106395105-70b11b80-63ce-11eb-9391-61282809d477.png)
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'model_transporter'
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ Sync updates for a model via:
20
+
21
+ ```ruby
22
+ class MyModel < ApplicationRecord
23
+ notifies_model_updates channel: -> { MyChannel.broadcasting_for(self) }
24
+ end
25
+ ```
26
+
27
+ The `channel` tells `ModelTransporter` which listeners to notify, and also serves as a grouping key for updates within a single web request. In the above example, if you had a channel defined as:
28
+
29
+ ```ruby
30
+ class MyChannel < ApplicationCable::Channel
31
+ def subscribed
32
+ my_model = MyModel.find(params[:id])
33
+ stream_for my_model
34
+ end
35
+ end
36
+ ```
37
+
38
+ Then any client connected to that channel would receive push updates for changes to that model.
39
+
40
+ If you had a TodoList app with `TodoList` objects that were shared between users, `Todo`s that belong to `TodoList`s, and `TodoComment`s that belong to `Todo`s, you could set it up as follows to ensure all clients on the same `TodoList` page get real-time updates from other users to stay in sync:
41
+
42
+ ```ruby
43
+ class TodoList < ApplicationRecord
44
+ has_many :todos, dependent: :destroy
45
+
46
+ notifies_model_updates channel: -> { TodoListChannel.broadcasting_for(self) }
47
+ end
48
+
49
+ class Todo < ApplicationRecord
50
+ belongs_to :todo_list
51
+ has_many :todo_comments, dependent: :destroy
52
+
53
+ notifies_model_updates channel: -> { TodoListChannel.broadcasting_for(todo_list) }
54
+ end
55
+
56
+ class TodoComment < ApplicationRecord
57
+ belongs_to :todo
58
+
59
+ notifies_model_updates channel: -> { TodoListChannel.broadcasting_for(todo.todo_list) }
60
+ end
61
+ ```
62
+
63
+ Since all 3 objects use the same parent `TodoList` object, any request that updates one or more of these objects at the same time, e.g. deleting a `Todo` and its dependent comments, would batch all of those changes and send them to everyone listening on the `TodoListChannel` for that `TodoList`.
64
+
65
+ ## Payload format
66
+
67
+ Payloads follow a simple standard format:
68
+
69
+ ```
70
+ {
71
+ type: 'server_event/MODEL_UPDATES',
72
+ actor_id: ACTOR_ID,
73
+ {
74
+ creates: {
75
+ MODEL_NAME: {
76
+ MODEL_ID: MODEL_JSON
77
+ },
78
+ MODEL_2_NAME: { ... }
79
+ }
80
+ updates: {
81
+ MODEL_NAME: {
82
+ MODEL_ID: MODEL_JSON
83
+ },
84
+ MODEL_2_NAME: { ... }
85
+ }
86
+ deletes: {
87
+ MODEL_NAME: {
88
+ MODEL_ID: {}
89
+ },
90
+ MODEL_2_NAME: { ... }
91
+ }
92
+ }
93
+ }
94
+ ```
95
+
96
+ `ModelTransporter` simply sends these messages, it is your job to handle them on the client side in the way that makes sense, e.g. by objects in your Redux store.
97
+
98
+ ## Configuration options
99
+
100
+ ```ruby
101
+ ModelTransporter.configure do |config|
102
+ config.actor = :current_user
103
+ config.push_adapter = MyPushAdapter.new
104
+ end
105
+ ```
106
+
107
+ - `actor`: `ModelTransporter` includes an `actor_id` in message payloads, which can be useful if you want to determine who triggered a model update. If you have a controller method called `current_user`, you can set `actor` equal to `:current_user`, and `actor_id` in transporter payloads will get set to that user
108
+ - `push_adapter`: by default `ModelTransporter` assumes you want to send updates via `ActionCable`. If you want to send updates in another way, e.g. something like `Pusher`, set a custom `push_adapter` to anything that responds to `push_update(channel, message)`.
109
+
110
+ ## Batching updates manually
111
+
112
+ If you want to batch updates outside of a web request, e.g. if you are updating models in a background job, or as a result of messages received over websockets, you can manually batch all updates inside of a block via:
113
+
114
+ ```ruby
115
+ ModelTransporter::BatchModelUpdates.batch_model_updates do
116
+ # update multiple models
117
+ end
118
+ ```
119
+
120
+ ## Run the specs
121
+
122
+ `rake spec`
123
+
124
+ ## License
125
+
126
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "model_transporter"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,20 @@
1
+ require 'active_support/all'
2
+ require "model_transporter/version"
3
+ require "model_transporter/configuration"
4
+ require "model_transporter/notifies_model_updates"
5
+ require "model_transporter/batch_model_updates"
6
+ require "model_transporter/controller_additions"
7
+ require "model_transporter/railtie"
8
+ require "model_transporter/push_adapter/action_cable"
9
+ require 'request_store'
10
+
11
+ module ModelTransporter
12
+ class Error < StandardError; end
13
+
14
+ mattr_accessor :configuration
15
+ @@configuration = Configuration.new
16
+
17
+ def self.configure
18
+ yield configuration
19
+ end
20
+ end
@@ -0,0 +1,77 @@
1
+ module ModelTransporter
2
+ module BatchModelUpdates
3
+ extend self
4
+ MODEL_UPDATES_EVENT = 'server_event/MODEL_UPDATES'
5
+ REQUEST_STORE_NAMESPACE = 'MODEL_TRANSPORTER'
6
+
7
+ def enqueue_model_updates(channel, message)
8
+ if updates_being_batched?
9
+ current_model_updates[channel] << message
10
+ else
11
+ cooked_message = base_model_update_message.merge(payload: message)
12
+ push_update(channel, cooked_message)
13
+ end
14
+ end
15
+
16
+ def with_transporter_actor(actor)
17
+ RequestStore.store["#{REQUEST_STORE_NAMESPACE}.transporter_actor"] = actor
18
+ yield
19
+ ensure
20
+ RequestStore.store.delete("#{REQUEST_STORE_NAMESPACE}.transporter_actor")
21
+ end
22
+
23
+ def batch_model_updates
24
+ RequestStore.store["#{REQUEST_STORE_NAMESPACE}.model_updates"] = Hash.new { |h, k| h[k] = [] }
25
+
26
+ yield
27
+ ensure
28
+ consolidate_model_updates.each do |channel, message|
29
+ push_update(channel, message)
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def transporter_actor_id
36
+ case actor = RequestStore.store["#{REQUEST_STORE_NAMESPACE}.transporter_actor"]
37
+ when Proc
38
+ actor.call&.id
39
+ else
40
+ actor&.id
41
+ end
42
+ end
43
+
44
+ def consolidate_model_updates
45
+ current_model_updates.each.with_object({}) do |(channel, messages), consolidated_messages|
46
+ consolidated_messages[channel] = messages.each.with_object(base_model_update_message) do |message, consolidated_message|
47
+ message.each do |update_type, updated_models|
48
+ updated_models.each do |model_name, models|
49
+ consolidated_message[:payload][update_type][model_name] ||= {}
50
+ consolidated_message[:payload][update_type][model_name].merge!(models)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ def base_model_update_message
58
+ {
59
+ type: MODEL_UPDATES_EVENT,
60
+ actor_id: transporter_actor_id,
61
+ payload: { creates: {}, updates: {}, deletes: {} }
62
+ }
63
+ end
64
+
65
+ def current_model_updates
66
+ RequestStore.store["#{REQUEST_STORE_NAMESPACE}.model_updates"]
67
+ end
68
+
69
+ def updates_being_batched?
70
+ !!current_model_updates
71
+ end
72
+
73
+ def push_update(channel, message)
74
+ ModelTransporter.configuration.push_adapter.push_update(channel, message)
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,10 @@
1
+ module ModelTransporter
2
+ class Configuration
3
+ attr_accessor :actor
4
+ attr_accessor :push_adapter
5
+
6
+ def initialize
7
+ @push_adapter = PushAdapter::ActionCable.new
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,21 @@
1
+ module ModelTransporter
2
+ module ControllerAdditions
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ around_action :batch_model_updates
7
+ end
8
+
9
+ def batch_model_updates(&block)
10
+ if ModelTransporter.configuration.actor
11
+ actor = Proc.new do
12
+ ModelTransporter.configuration.actor.to_proc.call(self)
13
+ end
14
+ end
15
+
16
+ ModelTransporter::BatchModelUpdates.with_transporter_actor(actor) do
17
+ ModelTransporter::BatchModelUpdates.batch_model_updates(&block)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,43 @@
1
+ module ModelTransporter::NotifiesModelUpdates
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ class_attribute :notifies_model_updates_options
6
+ self.notifies_model_updates_options = {}
7
+ end
8
+
9
+ class_methods do
10
+ def notifies_model_updates(channel:, id_key: :id, on: %i(create update destroy))
11
+ self.notifies_model_updates_options = { channel: channel, id_key: id_key }
12
+
13
+ if on.include?(:create)
14
+ after_create_commit -> { notify_model_updates(:creates, self) }
15
+ end
16
+
17
+ if on.include?(:update)
18
+ after_update_commit -> { notify_model_updates(:updates, self) }
19
+ end
20
+
21
+ if on.include?(:destroy)
22
+ after_destroy_commit -> { notify_model_updates(:deletes, {}) }
23
+ end
24
+ end
25
+ end
26
+
27
+ def notify_model_updates(update_type, model_state)
28
+ channel = instance_exec(&(self.class.notifies_model_updates_options[:channel]))
29
+ id_key = self.public_send(self.class.notifies_model_updates_options[:id_key])
30
+
31
+ payload = { creates: {}, updates: {}, deletes: {} }
32
+ payload[update_type] = {
33
+ self.class.name.pluralize.underscore => {
34
+ id_key => model_state
35
+ }
36
+ }
37
+
38
+ ModelTransporter::BatchModelUpdates.enqueue_model_updates(
39
+ channel,
40
+ payload
41
+ )
42
+ end
43
+ end
@@ -0,0 +1,9 @@
1
+ module ModelTransporter
2
+ module PushAdapter
3
+ class ActionCable
4
+ def push_update(channel, message)
5
+ ::ActionCable.server.broadcast(channel, message)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ require 'rails/railtie'
2
+
3
+ module ModelTransporter
4
+ class Railtie < Rails::Railtie
5
+ initializer "model_transporter.batch_model_updates.setup" do |app|
6
+ ActiveSupport.on_load(:action_controller) do
7
+ ActionController::Base.send(:include, ControllerAdditions)
8
+ end
9
+ end
10
+
11
+ initializer "model_transporter.notifies_model_updates.setup" do |app|
12
+ ActiveSupport.on_load(:active_record) do
13
+ ActiveRecord::Base.send(:include, NotifiesModelUpdates)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ module ModelTransporter
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,41 @@
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "model_transporter/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "model_transporter"
7
+ spec.version = ModelTransporter::VERSION
8
+ spec.authors = ["Andrew Warner"]
9
+ spec.email = ["wwarner.andrew@gmail.com"]
10
+
11
+ spec.summary = %q{Notifies listeners about model changes}
12
+ spec.description = %q{Notifies listeners about model changes}
13
+ spec.homepage = "https://github.com/a-warner/model_transporter"
14
+ spec.license = "MIT"
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = "https://github.com/a-warner/model_transporter"
18
+ spec.metadata["changelog_uri"] = "https://github.com/a-warner/model_transporter/blob/main/README.md"
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
23
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
+ end
25
+ spec.bindir = "exe"
26
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ["lib"]
28
+
29
+ spec.add_development_dependency "bundler", "~> 2.0"
30
+ spec.add_development_dependency "rake", "~> 13.0"
31
+ spec.add_development_dependency "rspec", "~> 3.0"
32
+ spec.add_development_dependency "rspec-rails"
33
+ spec.add_development_dependency "listen"
34
+ spec.add_development_dependency "sqlite3", "~> 1.4"
35
+ spec.add_development_dependency "sass-rails", '>= 6'
36
+ spec.add_development_dependency "webpacker", "~> 4.0"
37
+ spec.add_development_dependency "pry"
38
+
39
+ spec.add_dependency "rails", "~> 6.0"
40
+ spec.add_dependency "request_store"
41
+ end
metadata ADDED
@@ -0,0 +1,220 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: model_transporter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Andrew Warner
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-01-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-rails
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: listen
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: sqlite3
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.4'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.4'
97
+ - !ruby/object:Gem::Dependency
98
+ name: sass-rails
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '6'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '6'
111
+ - !ruby/object:Gem::Dependency
112
+ name: webpacker
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '4.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '4.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: pry
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rails
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '6.0'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '6.0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: request_store
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ description: Notifies listeners about model changes
168
+ email:
169
+ - wwarner.andrew@gmail.com
170
+ executables: []
171
+ extensions: []
172
+ extra_rdoc_files: []
173
+ files:
174
+ - ".gitignore"
175
+ - ".rspec"
176
+ - ".ruby-version"
177
+ - ".travis.yml"
178
+ - Gemfile
179
+ - Gemfile.lock
180
+ - LICENSE.txt
181
+ - README.md
182
+ - Rakefile
183
+ - bin/console
184
+ - bin/setup
185
+ - lib/model_transporter.rb
186
+ - lib/model_transporter/batch_model_updates.rb
187
+ - lib/model_transporter/configuration.rb
188
+ - lib/model_transporter/controller_additions.rb
189
+ - lib/model_transporter/notifies_model_updates.rb
190
+ - lib/model_transporter/push_adapter/action_cable.rb
191
+ - lib/model_transporter/railtie.rb
192
+ - lib/model_transporter/version.rb
193
+ - model_transporter.gemspec
194
+ homepage: https://github.com/a-warner/model_transporter
195
+ licenses:
196
+ - MIT
197
+ metadata:
198
+ homepage_uri: https://github.com/a-warner/model_transporter
199
+ source_code_uri: https://github.com/a-warner/model_transporter
200
+ changelog_uri: https://github.com/a-warner/model_transporter/blob/main/README.md
201
+ post_install_message:
202
+ rdoc_options: []
203
+ require_paths:
204
+ - lib
205
+ required_ruby_version: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - ">="
208
+ - !ruby/object:Gem::Version
209
+ version: '0'
210
+ required_rubygems_version: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - ">="
213
+ - !ruby/object:Gem::Version
214
+ version: '0'
215
+ requirements: []
216
+ rubygems_version: 3.1.2
217
+ signing_key:
218
+ specification_version: 4
219
+ summary: Notifies listeners about model changes
220
+ test_files: []