reactive-record 0.7.6 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8548152ff489f1a0eb74a6eb0acbe08bcf94acb0
4
- data.tar.gz: 2f6578db7396a607c8b3e61bea163fb55c5699c9
3
+ metadata.gz: e925fd65899df1cb77f96d9f3ccd69ec217c84b0
4
+ data.tar.gz: 758b5f711b45aa013975580fb6e35efe0e84d1b5
5
5
  SHA512:
6
- metadata.gz: daab93265cb69a09597a46ed12cafda5975abdba0ac6eddb82b74123448ced47ee3d39b889d9ad7fc28ddf85bc7999ff73db8fd69b7fe76b9ce540571b51132a
7
- data.tar.gz: e5ea4f5e44394b9103636a3b0081b7671caea1b90ab8627a5ba9b66976bcaaab212819da3e56aa3739a7903ef5cc1b98ddfb5fbbb7c1904ab6d9693241bef628
6
+ metadata.gz: 0488d3001210b59a6e041807c4766b9110986b9f66e6327eb06214252d874d5b8c6873e96897c92c8f7c7c0a24a1dacc56f64d947a09f883eaae4a338e2d1494
7
+ data.tar.gz: 6a37ddf21f528087ee68fea326eead883c740b7b61697106593a2089a58783173b9d8e0ecdfd263cce86d4987a9b6f7a76800afe9fa35857244b249a062c1d20
@@ -2,19 +2,19 @@ require 'reactive_record/server_data_cache'
2
2
 
3
3
  module ReactiveRecord
4
4
 
5
- class ReactiveRecordController < ApplicationController
5
+ class ReactiveRecordController < ::ApplicationController
6
6
 
7
7
  def fetch
8
- render :json => ReactiveRecord::ServerDataCache[params[:pending_fetches]]
8
+ render :json => ReactiveRecord::ServerDataCache[params[:pending_fetches], acting_user]
9
9
  end
10
10
 
11
11
 
12
12
  def save
13
- render :json => ReactiveRecord::Base.save_records(params[:models], params[:associations])
13
+ render :json => ReactiveRecord::Base.save_records(params[:models], params[:associations], acting_user)
14
14
  end
15
15
 
16
16
  def destroy
17
- render :json => ReactiveRecord::Base.destroy_record(params[:model], params[:id], params[:vector])
17
+ render :json => ReactiveRecord::Base.destroy_record(params[:model], params[:id], params[:vector], acting_user)
18
18
  end
19
19
 
20
20
  end
@@ -17,6 +17,7 @@ else
17
17
 
18
18
  require "opal"
19
19
  require "reactive_record/version"
20
+ require "reactive_record/permissions"
20
21
  require "reactive_record/engine"
21
22
  require "reactive_record/server_data_cache"
22
23
  require "reactive_record/active_record/reactive_record/isomorphic_base"
@@ -36,7 +36,9 @@ module ActiveRecord
36
36
 
37
37
  def inverse_of
38
38
  unless @options[:through] or @inverse_of
39
- inverse_association = klass.reflect_on_all_associations.detect { | association | association.association_foreign_key == @association_foreign_key }
39
+ inverse_association = klass.reflect_on_all_associations.detect do | association |
40
+ association.association_foreign_key == @association_foreign_key and association.klass.base_class == @owner_class.base_class
41
+ end
40
42
  raise "Association #{@owner_class}.#{attribute} (foreign_key: #{@association_foreign_key}) has no inverse in #{@klass_name}" unless inverse_association
41
43
  @inverse_of = inverse_association.attribute
42
44
  end
@@ -79,7 +79,9 @@ module ActiveRecord
79
79
  end
80
80
 
81
81
  [:belongs_to, :has_many, :has_one].each do |macro|
82
- define_method(macro) do |name, opts = {}|
82
+ define_method(macro) do |*args| # is this a bug in opal? saying name, scope=nil, opts={} does not work!
83
+ name = args.first
84
+ opts = args.last
83
85
  Associations::AssociationReflection.new(base_class, macro, name, opts)
84
86
  end
85
87
  end
@@ -11,8 +11,11 @@ module ActiveRecord
11
11
  @backing_record = hash
12
12
  else
13
13
  # standard active_record new -> creates a new instance, primary key is ignored if present
14
- hash[primary_key] = nil
15
- @backing_record = ReactiveRecord::Base.new(self.class, hash, self)
14
+ # we have to build the backing record first then initialize it so associations work correctly
15
+ @backing_record = ReactiveRecord::Base.new(self.class, {}, self)
16
+ @backing_record.instance_eval do
17
+ self.class.load_data { hash.each { |attribute, value| reactive_set!(attribute, value) unless attribute == primary_key } }
18
+ end
16
19
  end
17
20
  end
18
21
 
@@ -43,10 +43,14 @@ module ReactiveRecord
43
43
  self.class.data_loading?
44
44
  end
45
45
 
46
+ def self.load_data(&block)
47
+ current_data_loading, @data_loading = [@data_loading, true]
48
+ yield
49
+ @data_loading = current_data_loading
50
+ end
51
+
46
52
  def self.load_from_json(json, target = nil)
47
- @data_loading = true
48
- ServerDataCache.load_from_json(json, target)
49
- @data_loading = false
53
+ load_data { ServerDataCache.load_from_json(json, target) }
50
54
  end
51
55
 
52
56
  def self.class_scopes(model)
@@ -100,9 +104,9 @@ module ReactiveRecord
100
104
 
101
105
  def initialize(model, hash = {}, ar_instance = nil)
102
106
  @model = model
103
- @synced_attributes = {}
104
- @attributes = hash
105
107
  @ar_instance = ar_instance
108
+ @synced_attributes = {}
109
+ @attributes = {}
106
110
  records[model] << self
107
111
  end
108
112
 
@@ -203,7 +207,7 @@ module ReactiveRecord
203
207
  def sync!(hash = {})
204
208
  @attributes.merge! hash
205
209
  @synced_attributes = @attributes.dup
206
- @synced_attributes.each { |key, value| @synced_attributes[key] = value.dup if value.is_a? Collection }
210
+ @synced_attributes.each { |key, value| @synced_attributes[key] = value.dup_for_sync if value.is_a? Collection }
207
211
  @saving = false
208
212
  React::State.set_state(self, self, :synced) unless data_loading?
209
213
  self
@@ -13,6 +13,14 @@ module ReactiveRecord
13
13
  end
14
14
  @scopes = {}
15
15
  end
16
+
17
+ def dup_for_sync
18
+ self.dup.instance_eval do
19
+ @collection = @collection.dup if @collection
20
+ @scopes = @scopes.dup
21
+ self
22
+ end
23
+ end
16
24
 
17
25
  def all
18
26
  @dummy_collection.notify if @dummy_collection
@@ -55,10 +63,10 @@ module ReactiveRecord
55
63
 
56
64
 
57
65
  def <<(item)
58
- if @owner and @association and inverse_of = @association.inverse_of
66
+ backing_record = item.instance_variable_get(:@backing_record)
67
+ if backing_record and @owner and @association and inverse_of = @association.inverse_of
59
68
  item.attributes[inverse_of].attributes[@association.attribute].delete(item) if item.attributes[inverse_of] and item.attributes[inverse_of].attributes[@association.attribute]
60
69
  item.attributes[inverse_of] = @owner
61
- backing_record = item.instance_variable_get(:@backing_record)
62
70
  React::State.set_state(backing_record, inverse_of, @owner) unless backing_record.data_loading?
63
71
  end
64
72
  all << item unless all.include? item
@@ -6,10 +6,11 @@ module ReactiveRecord
6
6
 
7
7
  include React::IsomorphicHelpers
8
8
 
9
- before_first_mount do
9
+ before_first_mount do |context|
10
10
  if RUBY_ENGINE != 'opal'
11
- @server_data_cache = ReactiveRecord::ServerDataCache.new
11
+ @server_data_cache = ReactiveRecord::ServerDataCache.new(context.controller.acting_user)
12
12
  else
13
+ @fetch_scheduled = nil
13
14
  @records = Hash.new { |hash, key| hash[key] = [] }
14
15
  @class_scopes = Hash.new { |hash, key| hash[key] = {} }
15
16
  if on_opal_client?
@@ -150,26 +151,31 @@ module ReactiveRecord
150
151
 
151
152
  def self.schedule_fetch
152
153
  @fetch_scheduled ||= after(0.001) do
153
- last_fetch_at = @last_fetch_at
154
- pending_fetches = @pending_fetches.uniq
155
- log(["Server Fetching: %o", pending_fetches.to_n])
156
- start_time = Time.now
157
- HTTP.post(`window.ReactiveRecordEnginePath`, payload: {pending_fetches: pending_fetches}).then do |response|
158
- fetch_time = Time.now
159
- log(" Fetched in: #{(fetch_time-start_time).to_i}s")
160
- begin
161
- ReactiveRecord::Base.load_from_json(response.json)
162
- rescue Exception => e
163
- log("Exception raised while loading json from server: #{e}", :error)
154
+ if @pending_fetches.count > 0 # during testing we might reset the context while there are pending fetches
155
+ last_fetch_at = @last_fetch_at
156
+ pending_fetches = @pending_fetches.uniq
157
+ log(["Server Fetching: %o", pending_fetches.to_n])
158
+ start_time = Time.now
159
+ HTTP.post(`window.ReactiveRecordEnginePath`, payload: {pending_fetches: pending_fetches}).then do |response|
160
+ fetch_time = Time.now
161
+ log(" Fetched in: #{(fetch_time-start_time).to_i}s")
162
+ begin
163
+ ReactiveRecord::Base.load_from_json(response.json)
164
+ rescue Exception => e
165
+ log("Exception raised while loading json from server: #{e}", :error)
166
+ end
167
+ log(" Processed in: #{(Time.now-fetch_time).to_i}s")
168
+ log([" Returned: %o", response.json.to_n])
169
+ ReactiveRecord.run_blocks_to_load
170
+ ReactiveRecord::WhileLoading.loaded_at last_fetch_at
171
+ end.fail do |response|
172
+ log("Fetch failed", :error)
173
+ ReactiveRecord.run_blocks_to_load(response.body)
164
174
  end
165
- log(" Processed in: #{(Time.now-fetch_time).to_i}s")
166
- log([" Returned: %o", response.json.to_n])
167
- ReactiveRecord.run_blocks_to_load
168
- ReactiveRecord::WhileLoading.loaded_at last_fetch_at
169
- end if @pending_fetches.count > 0
170
- @pending_fetches = []
171
- @last_fetch_at = Time.now
172
- @fetch_scheduled = nil
175
+ @pending_fetches = []
176
+ @last_fetch_at = Time.now
177
+ @fetch_scheduled = nil
178
+ end
173
179
  end
174
180
  end
175
181
 
@@ -182,7 +188,7 @@ module ReactiveRecord
182
188
  if RUBY_ENGINE == 'opal'
183
189
 
184
190
  def save(&block)
185
-
191
+
186
192
  if data_loading?
187
193
 
188
194
  sync!
@@ -241,18 +247,29 @@ module ReactiveRecord
241
247
  internal_id, klass, attributes = item
242
248
  backing_records[internal_id].sync!(attributes)
243
249
  end
244
- yield response.json[:success], response.json[:message] if block
245
- promise.resolve response.json[:success], response.json[:message]
250
+ log("Reactive Record Save Failed: #{response.json[:message]}", :error) unless response.json[:success]
251
+ response.json[:saved_models].each do |model|
252
+ log(" Model: #{model[1]} Attributes: #{model[2]} Errors: #{model[3]}", :error) if model[3]
253
+ end
254
+ yield response.json[:success], response.json[:message], response.json[:saved_models] if block
255
+ promise.resolve response.json
246
256
  end
247
257
  promise
258
+ else
259
+ promise = Promise.new
260
+ yield true, nil if block
261
+ promise.resolve({success: true})
262
+ promise
248
263
  end
249
264
  end
250
265
 
251
266
  else
252
267
 
253
- def self.save_records(models, associations)
268
+ def self.save_records(models, associations, acting_user)
254
269
 
255
270
  reactive_records = {}
271
+ new_models = []
272
+ saved_models = []
256
273
 
257
274
  models.each do |model_to_save|
258
275
  attributes = model_to_save[:attributes]
@@ -262,43 +279,61 @@ module ReactiveRecord
262
279
  record = model.find(id)
263
280
  keys = record.attributes.keys
264
281
  attributes.each do |key, value|
265
- record[key] = value if keys.include? key
282
+ if keys.include? key
283
+ record[key] = value
284
+ else
285
+ record.send("#{key}=",value)
286
+ end
266
287
  end
267
288
  record
268
289
  else
269
290
  record = model.new
270
291
  keys = record.attributes.keys
271
292
  attributes.each do |key, value|
272
- record[key] = value if keys.include? key
293
+ if keys.include? key
294
+ record[key] = value
295
+ else
296
+ record.send("#{key}=",value)
297
+ end
273
298
  end
299
+ new_models << record
274
300
  record
275
301
  end
276
302
  end
277
303
 
278
- associations.each do |association|
279
- begin
280
- if reactive_records[association[:parent_id]].class.reflect_on_aggregation(association[:attribute].to_sym)
281
- reactive_records[association[:parent_id]].send("#{association[:attribute]}=", reactive_records[association[:child_id]])
282
- elsif reactive_records[association[:parent_id]].class.reflect_on_association(association[:attribute].to_sym).collection?
283
- reactive_records[association[:parent_id]].send("#{association[:attribute]}") << reactive_records[association[:child_id]]
304
+ ActiveRecord::Base.transaction do
305
+
306
+ associations.each do |association|
307
+ parent = reactive_records[association[:parent_id]]
308
+ parent.instance_variable_set("@reactive_record_#{association[:attribute]}_changed", true)
309
+ if parent.class.reflect_on_aggregation(association[:attribute].to_sym)
310
+ parent.send("#{association[:attribute]}=", reactive_records[association[:child_id]])
311
+ elsif parent.class.reflect_on_association(association[:attribute].to_sym).collection?
312
+ parent.send("#{association[:attribute]}") << reactive_records[association[:child_id]]
284
313
  else
285
- reactive_records[association[:parent_id]].send("#{association[:attribute]}=", reactive_records[association[:child_id]])
314
+ parent.send("#{association[:attribute]}=", reactive_records[association[:child_id]])
286
315
  end
287
- end
288
- end if associations
316
+ end if associations
317
+
318
+ has_errors = false
289
319
 
290
- saved_models = reactive_records.collect do |reactive_record_id, model|
291
- unless model.frozen?
292
- saved = model.save
293
- [reactive_record_id, model.class.name, model.attributes, saved]
294
- end
295
- end.compact
296
-
297
- {success: true, saved_models: saved_models || []}
320
+ saved_models = reactive_records.collect do |reactive_record_id, model|
321
+ unless model.frozen?
322
+ saved = model.check_permission_with_acting_user(acting_user, new_models.include?(model) ? :create_permitted? : :update_permitted?).save
323
+ has_errors ||= !saved
324
+ [reactive_record_id, model.class.name, model.attributes, (saved ? nil : model.errors.full_messages)]
325
+ end
326
+ end.compact
327
+
328
+ raise "Could not save all models" if has_errors
329
+
330
+ end
331
+
332
+ {success: true, saved_models: saved_models }
298
333
 
299
334
  rescue Exception => e
300
335
 
301
- {success: false, saved_models: saved_models || [], message: e.message}
336
+ {success: false, saved_models: saved_models, message: e.message}
302
337
 
303
338
  end
304
339
 
@@ -325,11 +360,11 @@ module ReactiveRecord
325
360
  if id or vector
326
361
  HTTP.post(`window.ReactiveRecordEnginePath`+"/destroy", payload: {model: ar_instance.model_name, id: id, vector: vector}).then do |response|
327
362
  yield response.json[:success], response.json[:message] if block
328
- promise.resolve response.json[:success], response.json[:message]
363
+ promise.resolve response.json
329
364
  end
330
365
  else
331
366
  yield true, nil if block
332
- promise.resolve true, nil
367
+ promise.resolve({success: true})
333
368
  end
334
369
 
335
370
  @attributes = {}
@@ -341,15 +376,16 @@ module ReactiveRecord
341
376
 
342
377
  else
343
378
 
344
- def self.destroy_record(model, id, vector)
379
+ def self.destroy_record(model, id, vector, acting_user)
345
380
  model = Object.const_get(model)
346
381
  record = if id
347
382
  model.find(id)
348
383
  else
349
- ServerDataCache.new[*vector]
384
+ ServerDataCache.new(acting_user)[*vector]
350
385
  end
351
- record.destroy
386
+ record.check_permission_with_acting_user(acting_user, :destroy_permitted?).destroy
352
387
  {success: true, attributes: {}}
388
+
353
389
  rescue Exception => e
354
390
  {success: false, record: record, message: e.message}
355
391
  end
@@ -23,14 +23,14 @@ module ReactiveRecord
23
23
  @loads_pending = true
24
24
  end
25
25
 
26
- def self.run_blocks_to_load
26
+ def self.run_blocks_to_load(failure = nil)
27
27
  if @blocks_to_load
28
28
  blocks_to_load = @blocks_to_load
29
29
  @blocks_to_load = []
30
30
  blocks_to_load.each do |promise_and_block|
31
31
  @loads_pending = nil
32
- result = promise_and_block.last.call
33
- if @loads_pending
32
+ result = promise_and_block.last.call(failure)
33
+ if @loads_pending and !failure
34
34
  @blocks_to_load << promise_and_block
35
35
  else
36
36
  promise_and_block.first.resolve result
@@ -0,0 +1,94 @@
1
+ class ActiveRecord::Base
2
+
3
+ attr_accessor :acting_user
4
+
5
+ def create_permitted?
6
+ true
7
+ end
8
+
9
+ def update_permitted?
10
+ true
11
+ end
12
+
13
+ def destroy_permitted?
14
+ true
15
+ end
16
+
17
+ def view_permitted?(attribute)
18
+ true
19
+ end
20
+
21
+ def only_changed?(*attributes)
22
+ (self.attributes.keys + self.class.reactive_record_association_keys).each do |key|
23
+ return false if self.send("#{key}_changed?") and !attributes.include? key
24
+ end
25
+ true
26
+ end
27
+
28
+ def none_changed?(*attributes)
29
+ attributes.each do |key|
30
+ return false if self.send("#{key}_changed?")
31
+ end
32
+ true
33
+ end
34
+
35
+ def any_changed?(*attributes)
36
+ attributes.each do |key|
37
+ return true if self.send("#{key}_changed?")
38
+ end
39
+ false
40
+ end
41
+
42
+ def all_changed?(*attributes)
43
+ attributes.each do |key|
44
+ return false unless self.send("#{key}_changed?")
45
+ end
46
+ true
47
+ end
48
+
49
+ class << self
50
+
51
+ attr_reader :reactive_record_association_keys
52
+
53
+ [:has_many, :belongs_to, :composed_of].each do |macro|
54
+ define_method "#{macro}_with_reactive_record_add_changed_method".to_sym do |attr_name, *args, &block|
55
+ define_method "#{attr_name}_changed?".to_sym do
56
+ instance_variable_get "@reactive_record_#{attr_name}_changed".to_sym
57
+ end
58
+ (@reactive_record_association_keys ||= []) << attr_name
59
+ send "#{macro}_without_reactive_record_add_changed_method".to_sym, attr_name, *args, &block
60
+ end
61
+ alias_method_chain macro, :reactive_record_add_changed_method
62
+ end
63
+
64
+ def belongs_to_with_reactive_record_add_is_method(attr_name, scope = nil, options = {})
65
+ define_method "#{attr_name}_is?".to_sym do |model|
66
+ send(options[:foreign_key] || "#{attr_name}_id") == model.id
67
+ end
68
+ belongs_to_without_reactive_record_add_is_method(attr_name, scope, options)
69
+ end
70
+
71
+ alias_method_chain :belongs_to, :reactive_record_add_is_method
72
+
73
+ end
74
+
75
+
76
+ def check_permission_with_acting_user(user, permission, *args)
77
+ old = acting_user
78
+ self.acting_user = user
79
+ if self.send(permission, *args)
80
+ self.acting_user = old
81
+ self
82
+ else
83
+ raise "ReactiveRecord Access Violation: #{permission}(#{args}) returned false"
84
+ end
85
+ end
86
+
87
+ end
88
+
89
+ class ActionController::Base
90
+
91
+ def acting_user
92
+ end
93
+
94
+ end
@@ -86,8 +86,9 @@ module ReactiveRecord
86
86
 
87
87
 
88
88
  class ServerDataCache
89
-
90
- def initialize
89
+
90
+ def initialize(acting_user)
91
+ @acting_user = acting_user
91
92
  @cache = []
92
93
  @requested_cache_items = []
93
94
  end
@@ -95,7 +96,7 @@ module ReactiveRecord
95
96
  if RUBY_ENGINE != 'opal'
96
97
 
97
98
  def [](*vector)
98
- root = CacheItem.new(@cache, vector[0])
99
+ root = CacheItem.new(@cache, @acting_user, vector[0])
99
100
  vector[1..-1].inject(root) { |cache_item, method| cache_item.apply_method method if cache_item }
100
101
  vector[0] = vector[0].constantize
101
102
  new_items = @cache.select { | cache_item | cache_item.root == root}
@@ -103,8 +104,8 @@ module ReactiveRecord
103
104
  new_items.last.value if new_items.last
104
105
  end
105
106
 
106
- def self.[](vectors)
107
- cache = new
107
+ def self.[](vectors, acting_user)
108
+ cache = new(acting_user)
108
109
  vectors.each { |vector| cache[*vector] }
109
110
  cache.as_json
110
111
  end
@@ -130,6 +131,7 @@ module ReactiveRecord
130
131
  attr_reader :vector
131
132
  attr_reader :record_chain
132
133
  attr_reader :root
134
+ attr_reader :acting_user
133
135
 
134
136
  def value
135
137
  @ar_object
@@ -139,7 +141,7 @@ module ReactiveRecord
139
141
  vector.last
140
142
  end
141
143
 
142
- def self.new(db_cache, klass)
144
+ def self.new(db_cache, acting_user, klass)
143
145
  klass_constant = klass.constantize
144
146
  if existing = db_cache.detect { |cached_item| cached_item.vector == [klass_constant] }
145
147
  return existing
@@ -147,9 +149,10 @@ module ReactiveRecord
147
149
  super
148
150
  end
149
151
 
150
- def initialize(db_cache, klass)
152
+ def initialize(db_cache, acting_user, klass)
151
153
  klass = klass.constantize
152
154
  @db_cache = db_cache
155
+ @acting_user = acting_user
153
156
  @vector = [klass]
154
157
  @ar_object = klass
155
158
  @record_chain = []
@@ -161,6 +164,9 @@ module ReactiveRecord
161
164
  def apply_method_to_cache(method, &block)
162
165
  @db_cache.inject(nil) do | representative, cache_item |
163
166
  if cache_item.vector == vector
167
+ if @ar_object.class < ActiveRecord::Base and @ar_object.attributes.has_key?(method)
168
+ @ar_object.check_permission_with_acting_user(acting_user, :view_permitted?, method)
169
+ end
164
170
  begin
165
171
  new_ar_object = yield cache_item
166
172
  cache_item.clone.instance_eval do
@@ -197,13 +203,8 @@ module ReactiveRecord
197
203
  else
198
204
  apply_method_to_cache(method) {[]}
199
205
  end
200
- else # @ar_object.respond_to? [*method].first
201
- puts "apply #{method} to #{@vector}"
202
- r = apply_method_to_cache(method) { |cache_item| cache_item.value.send(*method) }# rescue nil } # rescue in case we are on a nil association
203
- puts "representative method = #{r}"
204
- r
205
- #else
206
- # self
206
+ else
207
+ apply_method_to_cache(method) { |cache_item| cache_item.value.send(*method) }
207
208
  end
208
209
  end
209
210
 
@@ -1,3 +1,3 @@
1
1
  module ReactiveRecord
2
- VERSION = "0.7.6"
2
+ VERSION = "0.7.7"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reactive-record
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.6
4
+ version: 0.7.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mitch VanDuyn
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-28 00:00:00.000000000 Z
11
+ date: 2015-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -162,6 +162,7 @@ files:
162
162
  - lib/reactive_record/active_record/reactive_record/while_loading.rb
163
163
  - lib/reactive_record/engine.rb
164
164
  - lib/reactive_record/interval.rb
165
+ - lib/reactive_record/permissions.rb
165
166
  - lib/reactive_record/serializers.rb
166
167
  - lib/reactive_record/server_data_cache.rb
167
168
  - lib/reactive_record/version.rb