live_record 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -2
- data/{lib/live_record/.rspec → .rspec} +0 -0
- data/.travis.yml +0 -1
- data/Gemfile +3 -1
- data/README.md +363 -202
- data/Rakefile +5 -0
- data/app/assets/javascripts/live_record.coffee +4 -0
- data/app/assets/javascripts/live_record/helpers.coffee +4 -0
- data/app/assets/javascripts/live_record/helpers/load_records.coffee +13 -7
- data/app/assets/javascripts/live_record/helpers/spaceship.coffee +13 -0
- data/app/assets/javascripts/live_record/model.coffee +4 -0
- data/app/assets/javascripts/live_record/model/create.coffee +96 -27
- data/app/assets/javascripts/live_record/plugins.coffee +3 -0
- data/app/assets/javascripts/live_record/plugins/live_dom.coffee +5 -19
- data/app/assets/javascripts/live_record/plugins/live_dom/apply_to_model.coffee +17 -0
- data/app/channels/live_record/base_channel.rb +41 -0
- data/app/channels/live_record/changes_channel.rb +59 -0
- data/app/channels/live_record/publications_channel.rb +134 -0
- data/{lib/live_record/config.ru → config.ru} +0 -0
- data/lib/live_record.rb +2 -0
- data/lib/live_record/action_view_extensions/view_helper.rb +22 -0
- data/lib/live_record/configure.rb +19 -0
- data/lib/live_record/generators/install_generator.rb +9 -4
- data/lib/live_record/generators/templates/create_live_record_updates.rb +1 -1
- data/lib/live_record/generators/templates/index.html.erb +1 -0
- data/lib/live_record/generators/templates/model.rb.rb +4 -4
- data/lib/live_record/model/callbacks.rb +8 -2
- data/lib/live_record/version.rb +1 -1
- data/live_record.gemspec +2 -2
- data/{lib/live_record/spec → spec}/factories/posts.rb +0 -0
- data/spec/features/live_record_syncing_spec.rb +184 -0
- data/spec/helpers/wait.rb +19 -0
- data/{lib/live_record/spec → spec}/internal/app/assets/config/manifest.js +0 -0
- data/{lib/live_record/spec → spec}/internal/app/assets/javascripts/application.js +0 -0
- data/{lib/live_record/spec → spec}/internal/app/assets/javascripts/cable.js +0 -0
- data/spec/internal/app/assets/javascripts/posts.coffee +8 -0
- data/{lib/live_record/spec → spec}/internal/app/channels/application_cable/channel.rb +0 -0
- data/{lib/live_record/spec → spec}/internal/app/channels/application_cable/connection.rb +4 -4
- data/{lib/live_record/spec → spec}/internal/app/controllers/application_controller.rb +0 -0
- data/{lib/live_record/spec → spec}/internal/app/controllers/posts_controller.rb +1 -0
- data/{lib/live_record/spec → spec}/internal/app/models/application_record.rb +0 -0
- data/{lib/live_record/spec → spec}/internal/app/models/live_record_update.rb +0 -0
- data/spec/internal/app/models/post.rb +11 -0
- data/{lib/live_record/spec → spec}/internal/app/views/layouts/application.html.erb +0 -0
- data/{lib/live_record/spec → spec}/internal/app/views/posts/_form.html.erb +0 -0
- data/{lib/live_record/spec → spec}/internal/app/views/posts/_post.json.jbuilder +0 -0
- data/{lib/live_record/spec → spec}/internal/app/views/posts/edit.html.erb +0 -0
- data/{lib/live_record/spec → spec}/internal/app/views/posts/index.html.erb +6 -5
- data/{lib/live_record/spec → spec}/internal/app/views/posts/index.json.jbuilder +0 -0
- data/{lib/live_record/spec → spec}/internal/app/views/posts/new.html.erb +0 -0
- data/{lib/live_record/spec → spec}/internal/app/views/posts/show.html.erb +0 -0
- data/{lib/live_record/spec → spec}/internal/app/views/posts/show.json.jbuilder +0 -0
- data/{lib/live_record/spec → spec}/internal/config/cable.yml +0 -0
- data/{lib/live_record/spec → spec}/internal/config/database.yml +0 -0
- data/{lib/live_record/spec → spec}/internal/config/routes.rb +0 -0
- data/{lib/live_record/spec → spec}/internal/db/schema.rb +2 -0
- data/{lib/live_record/spec → spec}/internal/public/favicon.ico +0 -0
- data/{lib/live_record/spec → spec}/rails_helper.rb +4 -2
- data/{lib/live_record/spec → spec}/spec_helper.rb +0 -0
- metadata +64 -56
- data/app/assets/javascripts/live_record.js +0 -4
- data/app/assets/javascripts/live_record/helpers.js +0 -4
- data/app/assets/javascripts/live_record/model.js +0 -4
- data/app/assets/javascripts/live_record/plugins.js +0 -3
- data/lib/live_record/channel/implement.rb +0 -100
- data/lib/live_record/spec/features/live_record_syncing_spec.rb +0 -60
- data/lib/live_record/spec/internal/app/assets/javascripts/posts.coffee +0 -14
- data/lib/live_record/spec/internal/app/channels/live_record_channel.rb +0 -4
- data/lib/live_record/spec/internal/app/models/post.rb +0 -11
File without changes
|
data/lib/live_record.rb
CHANGED
@@ -6,6 +6,8 @@ Dir[__dir__ + '/live_record/*.rb'].each {|file| require file }
|
|
6
6
|
Dir[__dir__ + '/live_record/model/*.rb'].each {|file| require file }
|
7
7
|
Dir[__dir__ + '/live_record/channel/*.rb'].each {|file| require file }
|
8
8
|
Dir[__dir__ + '/live_record/generators/*.rb'].each {|file| require file }
|
9
|
+
Dir[__dir__ + '/live_record/overrides/*.rb'].each {|file| require file }
|
10
|
+
Dir[__dir__ + '/live_record/action_view_extensions/*.rb'].each {|file| require file }
|
9
11
|
|
10
12
|
module LiveRecord
|
11
13
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module LiveRecord
|
2
|
+
module ActionViewExtensions
|
3
|
+
module ViewHelper
|
4
|
+
def live_record_element(record)
|
5
|
+
raw " data-live-record-element='#{record.class.name}-#{record.id}' "
|
6
|
+
end
|
7
|
+
|
8
|
+
def live_record_updatable(record, attribute)
|
9
|
+
raise ArgumentError, "[#{record.class}] does not have an attribute named [#{attribute}]" unless record.attribute_names.include? attribute.to_s
|
10
|
+
raw " data-live-record-update-from='#{record.class.name}-#{record.id}-#{attribute}' "
|
11
|
+
end
|
12
|
+
|
13
|
+
def live_record_destroyable(record)
|
14
|
+
raw " data-live-record-destroy-from='#{record.class.name}-#{record.id}' "
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
ActiveSupport.on_load(:action_view) do
|
21
|
+
include LiveRecord::ActionViewExtensions::ViewHelper
|
22
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module LiveRecord
|
4
|
+
|
5
|
+
class Configuration < OpenStruct
|
6
|
+
end
|
7
|
+
|
8
|
+
@configuration = Configuration.new(
|
9
|
+
sync_record_buffer_time: 1.minute
|
10
|
+
)
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_accessor :configuration
|
14
|
+
|
15
|
+
def configure(&block)
|
16
|
+
block.call(@configuration)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -32,10 +32,15 @@ module LiveRecord
|
|
32
32
|
migration_template 'create_live_record_updates.rb', 'db/migrate/create_live_record_updates.rb'
|
33
33
|
end
|
34
34
|
|
35
|
-
def
|
36
|
-
|
37
|
-
|
38
|
-
end
|
35
|
+
# def copy_live_record_changes_channel_template
|
36
|
+
# class_collisions 'LiveRecordChangesChannel'
|
37
|
+
# template 'live_record_changes_channel.rb', File.join('app/channels', 'live_record_changes_channel.rb')
|
38
|
+
# end
|
39
|
+
|
40
|
+
# def copy_live_record_publication_channel_template
|
41
|
+
# class_collisions 'LiveRecordPublicationChannel'
|
42
|
+
# template 'live_record_publication_channel.rb', File.join('app/channels', 'live_record_publication_channel.rb')
|
43
|
+
# end
|
39
44
|
|
40
45
|
def update_application_javascript
|
41
46
|
in_root do
|
@@ -11,12 +11,12 @@ class <%= class_name %> < <%= parent_class_name.classify %>
|
|
11
11
|
<% end -%>
|
12
12
|
|
13
13
|
include LiveRecord::Model::Callbacks
|
14
|
-
has_many :live_record_updates, as: :recordable
|
14
|
+
has_many :live_record_updates, as: :recordable, dependent: :destroy
|
15
15
|
|
16
16
|
def self.live_record_whitelisted_attributes(<%= class_name.underscore %>, current_user)
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
# Add attributes to this array that you would like current_user to have access to.
|
18
|
+
# Defaults to empty array, thereby blocking everything by default, only unless explicitly stated here so.
|
19
|
+
[]
|
20
20
|
end
|
21
21
|
end
|
22
22
|
<% end -%>
|
@@ -7,6 +7,7 @@ module LiveRecord
|
|
7
7
|
before_update :__live_record_reference_changed_attributes__
|
8
8
|
after_update_commit :__live_record_broadcast_record_update__
|
9
9
|
after_destroy_commit :__live_record_broadcast_record_destroy__
|
10
|
+
after_create_commit :__live_record_broadcast_record_create__
|
10
11
|
|
11
12
|
def self.live_record_whitelisted_attributes(record, current_user)
|
12
13
|
[]
|
@@ -22,13 +23,18 @@ module LiveRecord
|
|
22
23
|
included_attributes = attributes.slice(*@_live_record_changed_attributes)
|
23
24
|
@_live_record_changed_attributes = nil
|
24
25
|
message_data = { 'action' => 'update', 'attributes' => included_attributes }
|
25
|
-
|
26
|
+
LiveRecord::ChangesChannel.broadcast_to(self, message_data)
|
26
27
|
LiveRecordUpdate.create!(recordable_type: self.class, recordable_id: self.id, created_at: DateTime.now)
|
27
28
|
end
|
28
29
|
|
29
30
|
def __live_record_broadcast_record_destroy__
|
30
31
|
message_data = { 'action' => 'destroy' }
|
31
|
-
|
32
|
+
LiveRecord::ChangesChannel.broadcast_to(self, message_data)
|
33
|
+
end
|
34
|
+
|
35
|
+
def __live_record_broadcast_record_create__
|
36
|
+
message_data = { 'action' => 'create', 'attributes' => attributes }
|
37
|
+
ActionCable.server.broadcast "live_record:publications:#{self.class.name.underscore}", message_data
|
32
38
|
end
|
33
39
|
end
|
34
40
|
end
|
data/lib/live_record/version.rb
CHANGED
data/live_record.gemspec
CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |s|
|
|
6
6
|
s.name = 'live_record'
|
7
7
|
s.version = LiveRecord::VERSION
|
8
8
|
s.summary = 'Rails 5 ActionCable Live JS Objects and DOM Elements'
|
9
|
-
s.description = "Auto-syncs records in client-side JS (through a Model DSL) from changes in the backend Rails server through ActionCable.\
|
9
|
+
s.description = "Auto-syncs records in client-side JS (through a Model DSL) from changes (updates/destroy) in the backend Rails server through ActionCable.\n Also supports streaming newly created records to client-side JS.\n Supports lost connection restreaming for both new records (create), and record-changes (updates/destroy).\n Auto-updates DOM elements mapped to a record attribute, from changes (updates/destroy)."
|
10
10
|
s.authors = ['Jules Roman B. Polidario']
|
11
11
|
s.email = 'jrpolidario@gmail.com'
|
12
12
|
s.files = `git ls-files`.split("\n")
|
@@ -16,6 +16,7 @@ Gem::Specification.new do |s|
|
|
16
16
|
|
17
17
|
s.add_dependency 'rails', '>= 5.0.0', '< 5.2'
|
18
18
|
|
19
|
+
s.add_development_dependency 'rails', '~> 5.1'
|
19
20
|
s.add_development_dependency 'bundler', '~> 1.3'
|
20
21
|
s.add_development_dependency 'rspec-rails', '~> 3.6'
|
21
22
|
s.add_development_dependency 'combustion', '~> 0.7'
|
@@ -27,7 +28,6 @@ Gem::Specification.new do |s|
|
|
27
28
|
s.add_development_dependency 'sprockets-rails', '~> 3.2'
|
28
29
|
s.add_development_dependency 'coffee-rails', '~> 4.2'
|
29
30
|
s.add_development_dependency 'jbuilder', '~> 2.7'
|
30
|
-
s.add_development_dependency 'capybara', '~> 2.15'
|
31
31
|
s.add_development_dependency 'chromedriver-helper', '~> 1.1'
|
32
32
|
s.add_development_dependency 'selenium-webdriver', '~> 3.5'
|
33
33
|
s.add_development_dependency 'faker', '~> 1.8'
|
File without changes
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
RSpec.feature 'LiveRecord Syncing', type: :feature do
|
4
|
+
let(:post1) { create(:post) }
|
5
|
+
let(:post2) { create(:post) }
|
6
|
+
let(:post3) { create(:post) }
|
7
|
+
let!(:posts) { [post1, post2, post3] }
|
8
|
+
|
9
|
+
scenario 'User sees live changes (updates) of post records', js: true do
|
10
|
+
visit '/posts'
|
11
|
+
|
12
|
+
post1_title_td = find('td', text: post1.title, wait: 10)
|
13
|
+
post2_title_td = find('td', text: post2.title, wait: 10)
|
14
|
+
post3_title_td = find('td', text: post3.title, wait: 10)
|
15
|
+
|
16
|
+
post1.update!(title: 'post1newtitle')
|
17
|
+
post2.update!(title: 'post2newtitle')
|
18
|
+
|
19
|
+
expect(post1_title_td).to have_content('post1newtitle', wait: 10)
|
20
|
+
expect(post2_title_td).to have_content('post2newtitle', wait: 10)
|
21
|
+
expect(post3_title_td).to have_content(post3.title, wait: 10)
|
22
|
+
end
|
23
|
+
|
24
|
+
scenario 'User sees live changes (destroy) of post records', js: true do
|
25
|
+
visit '/posts'
|
26
|
+
|
27
|
+
expect{find('td', text: post1.title, wait: 10)}.to_not raise_error
|
28
|
+
expect{find('td', text: post2.title, wait: 10)}.to_not raise_error
|
29
|
+
expect{find('td', text: post3.title, wait: 10)}.to_not raise_error
|
30
|
+
|
31
|
+
post1.destroy
|
32
|
+
post2.destroy
|
33
|
+
|
34
|
+
expect{find('td', text: post1.title)}.to raise_error Capybara::ElementNotFound
|
35
|
+
expect{find('td', text: post2.title)}.to raise_error Capybara::ElementNotFound
|
36
|
+
expect{find('td', text: post3.title)}.to_not raise_error
|
37
|
+
end
|
38
|
+
|
39
|
+
# see spec/internal/app/models/post.rb to view specified whitelisted attributes
|
40
|
+
scenario 'User sees live changes (updates) of post records, but only changes from whitelisted authorised attributes', js: true do
|
41
|
+
visit '/posts'
|
42
|
+
|
43
|
+
post1_title_td = find('td', text: post1.title, wait: 10)
|
44
|
+
post1_content_td = find('td', text: post1.content, wait: 10)
|
45
|
+
post2_title_td = find('td', text: post2.title, wait: 10)
|
46
|
+
post2_content_td = find('td', text: post2.content, wait: 10)
|
47
|
+
post3_title_td = find('td', text: post3.title, wait: 10)
|
48
|
+
post3_content_td = find('td', text: post3.content, wait: 10)
|
49
|
+
|
50
|
+
post1.update!(title: 'post1newtitle', content: 'post1newcontent')
|
51
|
+
post2.update!(title: 'post2newtitle', content: 'post2newcontent')
|
52
|
+
post3.update!(title: 'post3newtitle', content: 'post3newcontent')
|
53
|
+
|
54
|
+
expect(post1_title_td).to have_content('post1newtitle', wait: 10)
|
55
|
+
expect(post1_content_td).to_not have_content('post1newcontent')
|
56
|
+
expect(post2_title_td).to have_content('post2newtitle', wait: 10)
|
57
|
+
expect(post2_content_td).to_not have_content('post2newcontent')
|
58
|
+
expect(post3_title_td).to have_content('post3newtitle', wait: 10)
|
59
|
+
expect(post3_content_td).to_not have_content('post3newcontent')
|
60
|
+
end
|
61
|
+
|
62
|
+
# see spec/internal/app/views/posts/index.html.erb to see the subscribe "conditions"
|
63
|
+
scenario 'JS-Client receives live new (create) post records where specified "conditions" matched', js: true do
|
64
|
+
visit '/posts'
|
65
|
+
|
66
|
+
sleep(5)
|
67
|
+
|
68
|
+
post4 = create(:post, id: 98, is_enabled: true)
|
69
|
+
post5 = create(:post, id: 99, is_enabled: false)
|
70
|
+
|
71
|
+
wait before: -> { evaluate_script("LiveRecord.Model.all.Post.all[#{post4.id}] == undefined") }, becomes: -> (value) { value == false }
|
72
|
+
expect(evaluate_script("LiveRecord.Model.all.Post.all[#{post4.id}] == undefined")).to be false
|
73
|
+
|
74
|
+
wait before: -> { evaluate_script("LiveRecord.Model.all.Post.all[#{post5.id}] == undefined") }, becomes: -> (value) { value == true }
|
75
|
+
expect(evaluate_script("LiveRecord.Model.all.Post.all[#{post5.id}] == undefined")).to be true
|
76
|
+
end
|
77
|
+
|
78
|
+
# see spec/internal/app/views/posts/index.html.erb to see the subscribe "conditions"
|
79
|
+
scenario 'JS-Client receives live new (create) post records where only considered "conditions" are the whitelisted authorised attributes', js: true do
|
80
|
+
visit '/posts'
|
81
|
+
|
82
|
+
sleep(5)
|
83
|
+
|
84
|
+
# in index.html.erb:
|
85
|
+
# LiveRecord.Model.all.Post.subscribe({ where: { is_enabled: true, content: 'somecontent' }});
|
86
|
+
# because `content` is not whitelisted, therefore the `content` condition above is disregarded
|
87
|
+
post4 = create(:post, is_enabled: true, content: 'somecontent')
|
88
|
+
post5 = create(:post, is_enabled: true, content: 'contentisnotwhitelistedthereforewontbeconsidered')
|
89
|
+
|
90
|
+
wait before: -> { evaluate_script("LiveRecord.Model.all.Post.all[#{post4.id}] == undefined") }, becomes: -> (value) { value == false }
|
91
|
+
expect(evaluate_script("LiveRecord.Model.all.Post.all[#{post4.id}] == undefined")).to be false
|
92
|
+
|
93
|
+
wait before: -> { evaluate_script("LiveRecord.Model.all.Post.all[#{post5.id}] == undefined") }, becomes: -> (value) { value == false }
|
94
|
+
expect(evaluate_script("LiveRecord.Model.all.Post.all[#{post5.id}] == undefined")).to be false
|
95
|
+
end
|
96
|
+
|
97
|
+
# see spec/internal/app/models/post.rb to view specified whitelisted attributes
|
98
|
+
scenario 'JS-Client receives live new (create) post records having only the whitelisted authorised attributes', js: true do
|
99
|
+
visit '/posts'
|
100
|
+
|
101
|
+
sleep(5)
|
102
|
+
|
103
|
+
post4 = create(:post, is_enabled: true, title: 'sometitle', content: 'somecontent')
|
104
|
+
|
105
|
+
wait before: -> { evaluate_script("LiveRecord.Model.all.Post.all[#{post4.id}] == undefined") }, becomes: -> (value) { value == false }
|
106
|
+
expect(evaluate_script("LiveRecord.Model.all.Post.all[#{post4.id}].title()")).to eq post4.title
|
107
|
+
expect(evaluate_script("LiveRecord.Model.all.Post.all[#{post4.id}].content()")).to eq nil
|
108
|
+
end
|
109
|
+
|
110
|
+
# see spec/internal/app/models/post.rb to view specified whitelisted attributes
|
111
|
+
context 'when client got disconnected, and then reconnected' do
|
112
|
+
scenario 'JS-Client resyncs stale records', js: true do
|
113
|
+
post_that_will_be_updated_while_disconnected_1 = create(:post, is_enabled: true)
|
114
|
+
post_that_will_be_updated_while_disconnected_2 = create(:post, is_enabled: true)
|
115
|
+
|
116
|
+
visit '/posts'
|
117
|
+
|
118
|
+
sleep(5)
|
119
|
+
|
120
|
+
disconnection_time = 20 # seconds
|
121
|
+
|
122
|
+
Thread.new do
|
123
|
+
sleep(2)
|
124
|
+
|
125
|
+
# temporarily stop all current publication_channel connections
|
126
|
+
ObjectSpace.each_object(LiveRecord::ChangesChannel) do |changes_channel|
|
127
|
+
changes_channel.connection.close
|
128
|
+
end
|
129
|
+
|
130
|
+
# then we update records while disconnected
|
131
|
+
post_that_will_be_updated_while_disconnected_1.update!(title: 'newtitle')
|
132
|
+
post_that_will_be_updated_while_disconnected_2.update!(title: 'newtitle')
|
133
|
+
end
|
134
|
+
|
135
|
+
# LiveRecord.stop_all_streams
|
136
|
+
sleep(disconnection_time)
|
137
|
+
|
138
|
+
wait before: -> { evaluate_script("LiveRecord.Model.all.Post.all[#{post_that_will_be_updated_while_disconnected_1.id}] == undefined") }, becomes: -> (value) { value == false }, duration: 10.seconds
|
139
|
+
expect(evaluate_script("LiveRecord.Model.all.Post.all[#{post_that_will_be_updated_while_disconnected_1.id}].title()")).to eq 'newtitle'
|
140
|
+
|
141
|
+
wait before: -> { evaluate_script("LiveRecord.Model.all.Post.all[#{post_that_will_be_updated_while_disconnected_2.id}] == undefined") }, becomes: -> (value) { value == false }
|
142
|
+
expect(evaluate_script("LiveRecord.Model.all.Post.all[#{post_that_will_be_updated_while_disconnected_2.id}].title()")).to eq 'newtitle'
|
143
|
+
end
|
144
|
+
|
145
|
+
scenario 'JS-Client receives all post records created during the time it got disconnected', js: true do
|
146
|
+
visit '/posts'
|
147
|
+
|
148
|
+
sleep(5)
|
149
|
+
|
150
|
+
disconnection_time = 20 # seconds
|
151
|
+
|
152
|
+
post_created_before_disconnection = nil
|
153
|
+
post_created_while_disconnected_1 = nil
|
154
|
+
post_created_while_disconnected_2 = nil
|
155
|
+
|
156
|
+
Thread.new do
|
157
|
+
sleep(2)
|
158
|
+
|
159
|
+
# temporarily stop all current publication_channel connections
|
160
|
+
ObjectSpace.each_object(LiveRecord::PublicationsChannel) do |publication_channel|
|
161
|
+
publication_channel.connection.close
|
162
|
+
end
|
163
|
+
|
164
|
+
# then we create records while disconnected
|
165
|
+
post_created_while_disconnected_1 = create(:post, is_enabled: true, created_at: (DateTime.now - LiveRecord.configuration.sync_record_buffer_time) + 30.seconds)
|
166
|
+
post_created_while_disconnected_2 = create(:post, is_enabled: true, created_at: (DateTime.now - LiveRecord.configuration.sync_record_buffer_time) + 99.hours)
|
167
|
+
# we need to create this here, otherwise it will be loaded on the Page immediately by the .loadRecords() in JS
|
168
|
+
post_created_before_disconnection = create(:post, is_enabled: true, created_at: (DateTime.now - LiveRecord.configuration.sync_record_buffer_time) - 30.seconds)
|
169
|
+
end
|
170
|
+
|
171
|
+
# LiveRecord.stop_all_streams
|
172
|
+
sleep(disconnection_time)
|
173
|
+
|
174
|
+
wait before: -> { evaluate_script("LiveRecord.Model.all.Post.all[#{post_created_while_disconnected_1.id}] == undefined") }, becomes: -> (value) { value == false }, duration: 10.seconds
|
175
|
+
expect(evaluate_script("LiveRecord.Model.all.Post.all[#{post_created_while_disconnected_1.id}] == undefined")).to be false
|
176
|
+
|
177
|
+
wait before: -> { evaluate_script("LiveRecord.Model.all.Post.all[#{post_created_while_disconnected_2.id}] == undefined") }, becomes: -> (value) { value == false }
|
178
|
+
expect(evaluate_script("LiveRecord.Model.all.Post.all[#{post_created_while_disconnected_2.id}] == undefined")).to be false
|
179
|
+
|
180
|
+
wait before: -> { evaluate_script("LiveRecord.Model.all.Post.all[#{post_created_before_disconnection.id}] == undefined") }, becomes: -> (value) { value == false }
|
181
|
+
expect(evaluate_script("LiveRecord.Model.all.Post.all[#{post_created_before_disconnection.id}] == undefined")).to be true
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module SpecHelpers
|
2
|
+
module Wait
|
3
|
+
# Wait before the value of the "before" Proc becomes "becomes",
|
4
|
+
# but only wait until "duration" number of seconds,
|
5
|
+
# while checking the value each "interval" seconds interval.
|
6
|
+
def wait(duration: 5.seconds, interval: (0.5).second, before:, becomes:)
|
7
|
+
# use a different thread to prevent blocking the main thread due to sleep()
|
8
|
+
Thread.new do
|
9
|
+
start = Time.now
|
10
|
+
|
11
|
+
loop do
|
12
|
+
break if becomes.call(before.call)
|
13
|
+
sleep interval.seconds
|
14
|
+
break if (Time.now - start).seconds > duration
|
15
|
+
end
|
16
|
+
end.join
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Post < ApplicationRecord
|
2
|
+
include LiveRecord::Model::Callbacks
|
3
|
+
|
4
|
+
has_many :live_record_updates, as: :recordable, dependent: :destroy
|
5
|
+
|
6
|
+
def self.live_record_whitelisted_attributes(post, current_user)
|
7
|
+
# Add attributes to this array that you would like current_user to have access to.
|
8
|
+
# Defaults to empty array, thereby blocking everything by default, only unless explicitly stated here so.
|
9
|
+
[:title, :is_enabled, :created_at, :updated_at]
|
10
|
+
end
|
11
|
+
end
|
File without changes
|