all_futures 1.0.3 → 2.0.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.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +4 -1
  3. data/Gemfile.lock +272 -61
  4. data/LICENSE.txt +1 -1
  5. data/README.md +59 -79
  6. data/Rakefile +13 -1
  7. data/SUMMARY.md +22 -2
  8. data/bin/console +8 -0
  9. data/bin/loc +0 -0
  10. data/bin/setup +0 -0
  11. data/bin/standardize +0 -0
  12. data/lib/all_futures/association.rb +42 -0
  13. data/lib/all_futures/association_index.rb +69 -0
  14. data/lib/all_futures/attributes.rb +28 -0
  15. data/lib/all_futures/base.rb +66 -0
  16. data/lib/all_futures/callbacks.rb +71 -0
  17. data/lib/all_futures/configuration.rb +9 -0
  18. data/lib/all_futures/dirty.rb +116 -0
  19. data/lib/all_futures/embeds.rb +40 -0
  20. data/lib/all_futures/errors.rb +37 -0
  21. data/lib/all_futures/finder.rb +214 -0
  22. data/lib/all_futures/locale/en.yml +49 -0
  23. data/lib/all_futures/persistence.rb +595 -0
  24. data/lib/all_futures/presenter.rb +35 -0
  25. data/lib/all_futures/railtie.rb +26 -0
  26. data/lib/all_futures/translation.rb +22 -0
  27. data/lib/all_futures/validations.rb +10 -0
  28. data/lib/all_futures/version.rb +3 -1
  29. data/lib/all_futures/versions.rb +80 -0
  30. data/lib/all_futures.rb +24 -1
  31. data/lib/vendor/ACTIVE_ENTITY_MIT-LICENSE +42 -0
  32. data/lib/vendor/README.md +8 -0
  33. data/lib/vendor/active_entity/aggregations.rb +277 -0
  34. data/lib/vendor/active_entity/associations/embeds/association.rb +134 -0
  35. data/lib/vendor/active_entity/associations/embeds/builder/association.rb +105 -0
  36. data/lib/vendor/active_entity/associations/embeds/builder/collection_association.rb +71 -0
  37. data/lib/vendor/active_entity/associations/embeds/builder/embedded_in.rb +38 -0
  38. data/lib/vendor/active_entity/associations/embeds/builder/embeds_many.rb +13 -0
  39. data/lib/vendor/active_entity/associations/embeds/builder/embeds_one.rb +16 -0
  40. data/lib/vendor/active_entity/associations/embeds/builder/singular_association.rb +28 -0
  41. data/lib/vendor/active_entity/associations/embeds/collection_association.rb +209 -0
  42. data/lib/vendor/active_entity/associations/embeds/collection_proxy.rb +310 -0
  43. data/lib/vendor/active_entity/associations/embeds/embedded_in_association.rb +31 -0
  44. data/lib/vendor/active_entity/associations/embeds/embeds_many_association.rb +15 -0
  45. data/lib/vendor/active_entity/associations/embeds/embeds_one_association.rb +26 -0
  46. data/lib/vendor/active_entity/associations/embeds/singular_association.rb +35 -0
  47. data/lib/vendor/active_entity/associations.rb +168 -0
  48. data/lib/vendor/active_entity/attribute_assignment.rb +87 -0
  49. data/lib/vendor/active_entity/attribute_decorators.rb +90 -0
  50. data/lib/vendor/active_entity/attribute_methods/before_type_cast.rb +78 -0
  51. data/lib/vendor/active_entity/attribute_methods/dirty.rb +180 -0
  52. data/lib/vendor/active_entity/attribute_methods/primary_key.rb +96 -0
  53. data/lib/vendor/active_entity/attribute_methods/query.rb +38 -0
  54. data/lib/vendor/active_entity/attribute_methods/read.rb +44 -0
  55. data/lib/vendor/active_entity/attribute_methods/serialization.rb +90 -0
  56. data/lib/vendor/active_entity/attribute_methods/time_zone_conversion.rb +93 -0
  57. data/lib/vendor/active_entity/attribute_methods/write.rb +54 -0
  58. data/lib/vendor/active_entity/attribute_methods.rb +833 -0
  59. data/lib/vendor/active_entity/attributes.rb +240 -0
  60. data/lib/vendor/active_entity/base.rb +293 -0
  61. data/lib/vendor/active_entity/callbacks.rb +21 -0
  62. data/lib/vendor/active_entity/coders/json.rb +15 -0
  63. data/lib/vendor/active_entity/coders/yaml_column.rb +50 -0
  64. data/lib/vendor/active_entity/core.rb +348 -0
  65. data/lib/vendor/active_entity/enum.rb +260 -0
  66. data/lib/vendor/active_entity/errors.rb +69 -0
  67. data/lib/vendor/active_entity/gem_version.rb +17 -0
  68. data/lib/vendor/active_entity/inheritance.rb +176 -0
  69. data/lib/vendor/active_entity/integration.rb +78 -0
  70. data/lib/vendor/active_entity/locale/en.yml +45 -0
  71. data/lib/vendor/active_entity/model_schema.rb +118 -0
  72. data/lib/vendor/active_entity/nested_attributes.rb +554 -0
  73. data/lib/vendor/active_entity/persistence.rb +20 -0
  74. data/lib/vendor/active_entity/railtie.rb +76 -0
  75. data/lib/vendor/active_entity/readonly_attributes.rb +55 -0
  76. data/lib/vendor/active_entity/reflection.rb +447 -0
  77. data/lib/vendor/active_entity/serialization.rb +28 -0
  78. data/lib/vendor/active_entity/store.rb +291 -0
  79. data/lib/vendor/active_entity/translation.rb +24 -0
  80. data/lib/vendor/active_entity/type/date.rb +9 -0
  81. data/lib/vendor/active_entity/type/date_time.rb +9 -0
  82. data/lib/vendor/active_entity/type/internal/timezone.rb +17 -0
  83. data/lib/vendor/active_entity/type/json.rb +30 -0
  84. data/lib/vendor/active_entity/type/modifiers/array.rb +72 -0
  85. data/lib/vendor/active_entity/type/modifiers/array_without_blank.rb +19 -0
  86. data/lib/vendor/active_entity/type/registry.rb +112 -0
  87. data/lib/vendor/active_entity/type/serialized.rb +71 -0
  88. data/lib/vendor/active_entity/type/text.rb +11 -0
  89. data/lib/vendor/active_entity/type/time.rb +21 -0
  90. data/lib/vendor/active_entity/type/unsigned_integer.rb +17 -0
  91. data/lib/vendor/active_entity/type.rb +75 -0
  92. data/lib/vendor/active_entity/validate_embeds_association.rb +300 -0
  93. data/lib/vendor/active_entity/validations/absence.rb +25 -0
  94. data/lib/vendor/active_entity/validations/associated.rb +60 -0
  95. data/lib/vendor/active_entity/validations/length.rb +26 -0
  96. data/lib/vendor/active_entity/validations/presence.rb +68 -0
  97. data/lib/vendor/active_entity/validations/subset.rb +76 -0
  98. data/lib/vendor/active_entity/validations/uniqueness_in_embeds.rb +91 -0
  99. data/lib/vendor/active_entity/validations/uniqueness_on_active_record.rb +234 -0
  100. data/lib/vendor/active_entity/validations.rb +47 -0
  101. data/lib/vendor/active_entity/version.rb +10 -0
  102. data/lib/vendor/active_entity.rb +99 -0
  103. data/lib/vendor/core_ext/array_without_blank.rb +48 -0
  104. metadata +175 -21
  105. data/lib/all_futures/all_futures.rb +0 -28
  106. data/lib/all_futures/config.rb +0 -14
data/bin/console CHANGED
@@ -4,4 +4,12 @@ require "bundler/setup"
4
4
  require "all_futures"
5
5
  require "pry"
6
6
 
7
+ # Configure Kredis to allow for testing without Redis in order to avoid exception:
8
+ # NoMethodError: undefined method `config_for' for nil:NilClass
9
+ Kredis.configurator = Class.new {
10
+ def config_for(name)
11
+ {db: "1"}
12
+ end
13
+ }.new
14
+
7
15
  Pry.start
data/bin/loc CHANGED
File without changes
data/bin/setup CHANGED
File without changes
data/bin/standardize CHANGED
File without changes
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AllFutures
4
+ module Association
5
+ def initialize_attributes(record, attributes = {})
6
+ record.assign_attributes attributes if attributes.any?
7
+ record._write_attribute(reflection.options[:foreign_key], owner.id) if owner.is_a?(AllFutures::Base)
8
+ set_inverse_instance(record)
9
+ end
10
+ end
11
+
12
+ module CollectionAssociationHydration
13
+ def reader
14
+ AssociationIndex.hydrate(self)
15
+ super
16
+ end
17
+
18
+ def size
19
+ AssociationIndex.hydrate(self)
20
+ super
21
+ end
22
+ end
23
+
24
+ module SingularAssociationHydration
25
+ def reader
26
+ AssociationIndex.hydrate(self)
27
+ super
28
+ end
29
+ end
30
+ end
31
+
32
+ class ActiveEntity::Associations::Embeds::Association
33
+ prepend AllFutures::Association
34
+ end
35
+
36
+ class ActiveEntity::Associations::Embeds::CollectionAssociation
37
+ prepend AllFutures::CollectionAssociationHydration
38
+ end
39
+
40
+ class ActiveEntity::Associations::Embeds::SingularAssociation
41
+ prepend AllFutures::SingularAssociationHydration
42
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AllFutures
4
+ # Maintains Redis SETs that index embedded children by owner so associations
5
+ # can be lazy-loaded after find without scanning every key of the child class.
6
+ #
7
+ # Key shape: "OwnerClass:owner_id:association_name" => SET of child ids
8
+ module AssociationIndex
9
+ module_function
10
+
11
+ def key(owner_class, owner_id, association_name)
12
+ "#{owner_class.name}:#{owner_id}:#{association_name}"
13
+ end
14
+
15
+ def add(owner_class, owner_id, association_name, child_id)
16
+ return if owner_id.blank? || child_id.blank?
17
+ Kredis.redis.sadd(key(owner_class, owner_id, association_name), child_id.to_s)
18
+ end
19
+
20
+ def remove(owner_class, owner_id, association_name, child_id)
21
+ return if owner_id.blank? || child_id.blank?
22
+ Kredis.redis.srem(key(owner_class, owner_id, association_name), child_id.to_s)
23
+ end
24
+
25
+ def clear(owner_class, owner_id, association_name)
26
+ return if owner_id.blank?
27
+ Kredis.redis.del(key(owner_class, owner_id, association_name))
28
+ end
29
+
30
+ def member_ids(owner_class, owner_id, association_name)
31
+ return [] if owner_id.blank?
32
+ Array(Kredis.redis.smembers(key(owner_class, owner_id, association_name)))
33
+ end
34
+
35
+ def hydrate(association)
36
+ return if association.instance_variable_get(:@af_hydrated)
37
+ association.instance_variable_set(:@af_hydrated, true)
38
+
39
+ owner = association.owner
40
+ return unless owner.is_a?(AllFutures::Base) && owner.persisted?
41
+
42
+ reflection = association.reflection
43
+ return unless [:embeds_many, :embeds_one].include?(reflection.macro)
44
+
45
+ ids = member_ids(owner.class, owner.id, reflection.name)
46
+ return if ids.empty?
47
+
48
+ existing_ids = Array.wrap(association.target).compact.map { |r| r.id.to_s }
49
+
50
+ ids.each do |child_id|
51
+ next if existing_ids.include?(child_id.to_s)
52
+
53
+ begin
54
+ record = reflection.klass.find(child_id)
55
+ rescue AllFutures::RecordNotFound
56
+ remove(owner.class, owner.id, reflection.name, child_id)
57
+ next
58
+ end
59
+
60
+ if reflection.macro == :embeds_many
61
+ association.add_to_target(record, true)
62
+ else
63
+ association.target = record
64
+ association.set_inverse_instance(record)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AllFutures
4
+ module Attributes
5
+ extend ActiveSupport::Concern
6
+
7
+ class_methods do
8
+ def has_future(name, klass, **options)
9
+ ivar_symbol = :"@#{name}_all_futures"
10
+
11
+ define_method(name) do
12
+ if instance_variable_defined?(ivar_symbol)
13
+ instance_variable_get(ivar_symbol)
14
+ else
15
+ af_key = if options[:key]
16
+ options[:key]
17
+ else
18
+ record_id = try(:id) or raise AllFutures::ParentModelNotSavedYet, "AllFutures requires a unique key. Either save the parent model before accessing #{name}, or pass a custom key."
19
+ "#{self.class.name.tableize.tr("/", ":")}:#{record_id}:#{name}"
20
+ end
21
+ af = klass.exists?(af_key) ? klass.find(af_key) : klass.new(id: af_key)
22
+ instance_variable_set(ivar_symbol, af)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AllFutures
4
+ class Base < ActiveEntity::Base
5
+ prepend ::AllFutures::Callbacks
6
+ extend ::ActiveModel::Naming
7
+ extend ::AllFutures::Translation
8
+ include ::AllFutures::Persistence
9
+ include ::AllFutures::Dirty
10
+ include ::AllFutures::Validations
11
+ include ::AllFutures::Presenter
12
+ include ::AllFutures::Versions
13
+ include ::AllFutures::Finder
14
+ include ::AllFutures::Embeds
15
+ include ::ActiveModel::Conversion
16
+ include ::ActiveModel::SecurePassword
17
+ include ::ActiveRecord::Integration
18
+ include ::Kredis::Attributes
19
+
20
+ attr_reader :created_at, :updated_at
21
+
22
+ def initialize(attributes = {}, &block)
23
+ attributes ||= {}
24
+ attributes = attributes.attributes.transform_keys(&:to_sym) if attributes.is_a?(ActiveRecord::Base)
25
+ attributes_for_super = attributes.key?(:id) ? attributes.except(:id).except(:created_at).except(:updated_at) : attributes
26
+
27
+ super(attributes_for_super) do
28
+ @id = attributes&.fetch(:id, nil) || ULID.generate
29
+ @created_at = Time.current
30
+ @updated_at = attributes&.fetch(:updated_at, Time.current)
31
+ @redis_key = "#{self.class.name}:#{@id}"
32
+ @new_record = !self.class.exists?(@id)
33
+ @destroyed = false
34
+ @previously_new_record = false
35
+ @_versioning_enabled = self.class.versioning
36
+ @_versions = {}
37
+ @_current_version = nil
38
+ @_id_set = attributes.key?(:id)
39
+
40
+ @attributes.keys.each do |attr|
41
+ define_singleton_method("#{attr}_changed?") { attribute_changed?(attr) }
42
+ define_singleton_method("#{attr}_valid?") { attribute_valid?(attr) }
43
+ define_singleton_method("rollback_#{attr}") { rollback_attribute(attr) }
44
+ define_singleton_method("rollback_#{attr}!") { rollback_attribute!(attr) }
45
+ define_singleton_method("restore_#{attr}") { restore_attribute(attr) }
46
+ define_singleton_method("restore_#{attr}!") { restore_attribute(attr) }
47
+ end
48
+
49
+ block&.call(self)
50
+ end
51
+ end
52
+
53
+ def id
54
+ (!new_record? || @_id_set) ? @id.to_s : nil
55
+ end
56
+
57
+ def id=(value)
58
+ raise FrozenError.new("can't modify id when persisted") unless new_record?
59
+ @id = value.to_s
60
+ @redis_key = "#{self.class.name}:#{@id}"
61
+ @_id_set = true
62
+ end
63
+ end
64
+
65
+ ActiveSupport.run_load_hooks(:all_futures, Base)
66
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/callbacks"
4
+
5
+ module AllFutures
6
+ module Callbacks
7
+ extend ActiveSupport::Concern
8
+
9
+ CALLBACKS = [:before_save, :after_save, :before_update, :after_update, :before_destroy, :after_destroy]
10
+
11
+ def self.prepended(base)
12
+ base.include(ActiveSupport::Callbacks)
13
+
14
+ base.define_callbacks(:save, :update, :destroy, skip_after_callbacks_if_terminated: true) unless base.respond_to?(:_perform_callbacks) && base._perform_callbacks.present?
15
+
16
+ class << base
17
+ prepend ClassMethods
18
+ end
19
+ end
20
+
21
+ def destroy
22
+ perform_operation(:destroy)
23
+ end
24
+
25
+ def destroy!
26
+ perform_operation(:destroy!)
27
+ end
28
+
29
+ def save
30
+ perform_operation(:save)
31
+ end
32
+
33
+ def save!
34
+ perform_operation(:save!)
35
+ end
36
+
37
+ def update(attrs = {})
38
+ perform_operation(:update, attrs)
39
+ end
40
+
41
+ def update!(attrs = {})
42
+ perform_operation(:update!, attrs)
43
+ end
44
+
45
+ def perform_operation(operation, *args)
46
+ if respond_to?(:run_callbacks)
47
+ callback = operation.to_s.sub("!", "").to_sym
48
+ run_callbacks callback do
49
+ method(operation).super_method.call(*args)
50
+ end
51
+ else
52
+ method(operation).super_method.call(*args)
53
+ end
54
+ end
55
+
56
+ module ClassMethods
57
+ def method_missing(name, *filters, &blk)
58
+ if CALLBACKS.include? name
59
+ callback_context, method_name = name.to_s.split("_")
60
+ set_callback(method_name.to_sym, callback_context.to_sym, *filters, &blk)
61
+ else
62
+ super
63
+ end
64
+ end
65
+
66
+ def respond_to_missing?(name, include_all)
67
+ CALLBACKS.include?(name) || super
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AllFutures
4
+ # When true, versioned models save via a Redis Lua compare-and-set so two
5
+ # processes cannot both pass a stale check and silently clobber each other.
6
+ # Default false: the in-process guard rail (GET, check, SET) is enough for
7
+ # most apps and avoids an EVAL on every write.
8
+ mattr_accessor :atomic_locking, instance_accessor: false, default: false
9
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AllFutures
4
+ module Dirty
5
+ extend ActiveSupport::Concern
6
+
7
+ def attribute_change(attribute)
8
+ _raise_unknown_attribute_error(attribute) unless attributes.key?(attribute.to_s)
9
+ (attribute_was(attribute) == self[attribute]) ? nil : [attribute_was(attribute), self[attribute]]
10
+ end
11
+
12
+ def attribute_changed?(attribute)
13
+ _raise_unknown_attribute_error(attribute) unless attributes.key?(attribute.to_s)
14
+ changes.key? attribute.to_s
15
+ end
16
+ alias_method :attribute_will_change?, :attribute_changed?
17
+ alias_method :will_save_change_to_attribute?, :attribute_changed?
18
+
19
+ def attribute_changed!(attribute)
20
+ _raise_unknown_attribute_error(attribute) unless attributes.key?(attribute.to_s)
21
+ public_send("#{attribute}_will_change!")
22
+ end
23
+
24
+ def attribute_previous_change(attribute)
25
+ super
26
+ end
27
+
28
+ def attribute_will_change!(attribute)
29
+ super
30
+ end
31
+
32
+ def clear_attribute_change(attribute)
33
+ _raise_unknown_attribute_error(attribute) unless attributes.key?(attribute.to_s)
34
+ super
35
+ end
36
+
37
+ def clear_attribute_changes(attr_names = changed)
38
+ super
39
+ end
40
+
41
+ def dirty?
42
+ changes.any?
43
+ end
44
+ alias_method :changed_attributes?, :dirty?
45
+ alias_method :has_changes_to_save?, :dirty?
46
+
47
+ def previous_attributes
48
+ attribute_names.each_with_object({}) do |attribute, hash|
49
+ hash[attribute] = attribute_previously_was(attribute)
50
+ end
51
+ end
52
+
53
+ def mutations_before_last_save
54
+ super
55
+ end
56
+
57
+ def restore_attribute(attribute)
58
+ _raise_unknown_attribute_error(attribute) unless attributes.key?(attribute.to_s)
59
+ attribute = attribute.to_s
60
+ if attribute_changed?(attribute)
61
+ self[attribute] = attribute_was(attribute)
62
+ clear_attribute_change(attribute)
63
+ end
64
+ end
65
+
66
+ def restore_attributes(attr_names = changed)
67
+ attr_names.each { |attribute| _raise_unknown_attribute_error(attribute) unless attributes.key?(attribute.to_s) }.each { |attribute| restore_attribute(attribute) }
68
+ end
69
+
70
+ def rollback_attribute(attribute)
71
+ _raise_unknown_attribute_error(attribute) unless attributes.key?(attribute.to_s)
72
+ if self[attribute] != attribute_previously_was(attribute)
73
+ self[attribute] = attribute_previously_was(attribute)
74
+ clear_attribute_change(attribute)
75
+ end
76
+ end
77
+
78
+ def rollback_attribute!(attribute)
79
+ _raise_unknown_attribute_error(attribute) unless attributes.key?(attribute.to_s)
80
+ # unlike rollback_attribute, keep the mutation tracked so save sees a dirty record
81
+ self[attribute] = attribute_previously_was(attribute) if self[attribute] != attribute_previously_was(attribute)
82
+ save
83
+ end
84
+
85
+ def rollback_attributes(attr_names = changed)
86
+ attr_names.each { |attribute| _raise_unknown_attribute_error(attribute) unless attributes.key?(attribute.to_s) }.each { |attribute| rollback_attribute(attribute) }
87
+ end
88
+
89
+ def rollback_attributes!(attr_names = changed)
90
+ attr_names.each { |attribute| _raise_unknown_attribute_error(attribute) unless attributes.key?(attribute.to_s) }
91
+ attr_names.each { |attribute| self[attribute] = attribute_previously_was(attribute) if self[attribute] != attribute_previously_was(attribute) }
92
+ save
93
+ end
94
+
95
+ def saved_changes?
96
+ saved_changes.any?
97
+ end
98
+ alias_method :previous_changes?, :saved_changes?
99
+
100
+ def saved_changes
101
+ attributes.select { |attribute| attribute_previously_changed? attribute }
102
+ end
103
+
104
+ module ClassMethods
105
+ def set_previous_attributes(model, record)
106
+ tracker = ActiveModel::AttributeMutationTracker.new(model.instance_variable_get(:@attributes))
107
+ previous_values = tracker.instance_variable_get(:@attributes).instance_variable_get(:@attributes)
108
+ previous_values.each do |key, attribute|
109
+ original = attribute.instance_variable_get(:@original_attribute)
110
+ original&.instance_variable_set(:@value_before_type_cast, record["previous_attributes"][key])
111
+ end
112
+ model.instance_variable_set :@mutations_before_last_save, tracker
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AllFutures
4
+ module Embeds
5
+ extend ActiveSupport::Concern
6
+
7
+ class_methods do
8
+ def embedded_in(name, **options)
9
+ autosave = options.delete(:autosave)
10
+ dependent = options.delete(:dependent)
11
+ foreign_key = options.delete(:foreign_key)
12
+ embeds = super
13
+ embeds[name.to_s].options[:autosave] = autosave
14
+ embeds[name.to_s].options[:dependent] = dependent
15
+ # FK lives on the child and points at the parent: government_id, not spy_id
16
+ embeds[name.to_s].options[:foreign_key] = foreign_key || "#{name}_id"
17
+ end
18
+
19
+ def embeds_one(name, **options)
20
+ autosave = options.delete(:autosave)
21
+ dependent = options.delete(:dependent)
22
+ foreign_key = options.delete(:foreign_key)
23
+ embeds = super
24
+ embeds[name.to_s].options[:autosave] = autosave
25
+ embeds[name.to_s].options[:dependent] = dependent
26
+ embeds[name.to_s].options[:foreign_key] = foreign_key || model_name.singular + "_id"
27
+ end
28
+
29
+ def embeds_many(name, **options)
30
+ autosave = options.delete(:autosave)
31
+ dependent = options.delete(:dependent)
32
+ foreign_key = options.delete(:foreign_key)
33
+ embeds = super
34
+ embeds[name.to_s].options[:autosave] = autosave
35
+ embeds[name.to_s].options[:dependent] = dependent
36
+ embeds[name.to_s].options[:foreign_key] = foreign_key || model_name.singular + "_id"
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AllFutures
4
+ class DeleteRestrictionError < StandardError
5
+ def initialize(name = nil)
6
+ if name
7
+ super("Cannot delete record because of dependent #{name}")
8
+ else
9
+ super("Delete restriction error.")
10
+ end
11
+ end
12
+ end
13
+
14
+ class InvalidAttribute < StandardError; end
15
+
16
+ class InvalidDependentOption < StandardError; end
17
+
18
+ class MissingForeignKeyError < StandardError; end
19
+
20
+ class ParentModelNotSavedYet < StandardError; end
21
+
22
+ class ReadOnlyRecord < StandardError; end
23
+
24
+ class RecordInvalid < StandardError; end
25
+
26
+ class RecordNotFound < StandardError; end
27
+
28
+ class RecordNotDestroyed < StandardError; end
29
+
30
+ class RecordNotSaved < StandardError; end
31
+
32
+ class RecordStale < StandardError; end
33
+
34
+ class SoleRecordExceeded < StandardError; end
35
+
36
+ class VersionNotFound < StandardError; end
37
+ end