store_model 4.3.0 → 4.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c65c5b8e184e6b4f7c402a7a2a82df8228d2b55c7ad6352c3752ac988bc86943
4
- data.tar.gz: f2f404a6330ded65170e6256adb71c109592c6187a85d221d6887c965eeb9a1c
3
+ metadata.gz: b9c6db50613221bc69d952fdaed0cb2f1ae07a8c3730748e1166fb93d9538386
4
+ data.tar.gz: f40dae854bd0900ed4f79096fa721da565c6d472b9b187a367cb03f7b3cd2da8
5
5
  SHA512:
6
- metadata.gz: cf0146c740b94e5591d16794431120afc4c28dfb3477757571d4d77fb8833836fccdb94d5776f9199f92164ab36029def584d3a802ee186b531916d82c098e6b
7
- data.tar.gz: ae1753153b834b2b02bfa2ec4afc767540833eea27f59e653c3dbf8435bba3c1810999fba5128d71ce97e38e31314bc5622c8a01eb3054e743acd337bfae1b09
6
+ metadata.gz: 50a646560709d22bbb3a6c828cf7834e84dcc9998e1bebc619fcee0953a4b1962728573e18169444c28ef0fa49fcbfc88c3f3bb0de0a1828293a1397b4f13110
7
+ data.tar.gz: 684aa3e90eb4886709ad0960d1ff5092b6223d3393e9dc72276ef149262e82c549ac2de1727385655598e5c953e2f346a160daf15ce4df4f27e163af3a1a5c08
data/README.md CHANGED
@@ -122,10 +122,52 @@ def supplier_params
122
122
  end
123
123
  ```
124
124
 
125
+ ### ActiveAdmin Integration
126
+
127
+ If you're using [ActiveAdmin](https://activeadmin.info/), enable compatibility mode to make the `has_many` form helper work with StoreModel attributes:
128
+
129
+ ```ruby
130
+ # config/initializers/store_model.rb
131
+ StoreModel.config.active_admin_compatibility = true
132
+ ```
133
+
134
+ Example usage:
135
+
136
+ ```ruby
137
+ # app/models/supplier.rb
138
+ class Supplier
139
+ include StoreModel::Model
140
+
141
+ attribute :title, :string
142
+ attribute :address, :string
143
+ end
144
+
145
+ # app/models/product.rb
146
+ class Product < ApplicationRecord
147
+ include StoreModel::NestedAttributes
148
+
149
+ attribute :suppliers, Supplier.to_array_type
150
+ accepts_nested_attributes_for :suppliers, allow_destroy: true
151
+ end
152
+
153
+ # app/admin/products.rb
154
+ ActiveAdmin.register Product do
155
+ permit_params suppliers_attributes: [:title, :address, :_destroy]
156
+
157
+ form do |f|
158
+ f.has_many :suppliers, allow_destroy: true do |s|
159
+ s.input :title
160
+ s.input :address
161
+ end
162
+ f.actions
163
+ end
164
+ end
165
+ ```
166
+
125
167
  ## Documentation
126
168
 
127
169
  1. [Installation](./docs/installation.md)
128
- 2. StoreModel::Model API:
170
+ 2. `StoreModel::Model` API:
129
171
  * [Instantiation](./docs/instantiation.md)
130
172
  * [Validations](./docs/validations.md)
131
173
  * [Enums](./docs/enums.md)
@@ -10,8 +10,8 @@ module StoreModel
10
10
  # @param base_errors [ActiveModel::Errors] errors object of the parent record
11
11
  # @param _store_model_errors [ActiveModel::Errors] errors object of the
12
12
  # StoreModel::Model attribute
13
- def call(attribute, base_errors, _store_model_errors)
14
- base_errors.add(attribute, :invalid)
13
+ def call(attribute, base_errors, store_model_errors)
14
+ base_errors.add(attribute, :invalid, errors: store_model_errors)
15
15
  end
16
16
  end
17
17
  end
@@ -32,11 +32,19 @@ module StoreModel
32
32
  # @return [Boolean]
33
33
  attr_accessor :enable_parent_assignment
34
34
 
35
+ # Controls if ActiveAdmin compatibility patches are applied.
36
+ # When enabled, adds methods like `new_record?` and `reflect_on_association`
37
+ # that are expected by ActiveAdmin's form builders.
38
+ # Default: false
39
+ # @return [Boolean]
40
+ attr_accessor :active_admin_compatibility
41
+
35
42
  def initialize
36
43
  @serialize_unknown_attributes = true
37
44
  @enable_parent_assignment = true
38
45
  @serialize_enums_using_as_json = true
39
46
  @serialize_empty_attributes = true
47
+ @active_admin_compatibility = false
40
48
  end
41
49
  end
42
50
  end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StoreModel
4
+ # ActiveAdmin compatibility patches
5
+ #
6
+ # This module contains patches that make StoreModel compatible with ActiveAdmin's
7
+ # form builders, particularly the has_many helper which expects certain ActiveRecord-like
8
+ # methods to be present.
9
+ #
10
+ # To enable these patches, set:
11
+ # StoreModel.config.active_admin_compatibility = true
12
+ module ActiveAdminCompatibility
13
+ # Reflection class for StoreModel associations.
14
+ # This provides compatibility with form builders like ActiveAdmin's has_many
15
+ # that expect ActiveRecord-style reflection objects.
16
+ class Reflection
17
+ attr_reader :name, :klass
18
+
19
+ # @param name [Symbol] association name
20
+ # @param klass [Class] the StoreModel class
21
+ def initialize(name, klass)
22
+ @name = name
23
+ @klass = klass
24
+ end
25
+ end
26
+
27
+ # Patch for StoreModel::Model to add new_record? method
28
+ module NewRecordPatch
29
+ # Always returns true for StoreModel instances when ActiveAdmin compatibility is enabled.
30
+ # This is needed for compatibility with form builders like ActiveAdmin's has_many.
31
+ # For ActiveRecord models, delegates to the original implementation.
32
+ #
33
+ # @return [Boolean]
34
+ def new_record?
35
+ super
36
+ rescue NoMethodError
37
+ true
38
+ end
39
+ end
40
+
41
+ # Patch for StoreModel::NestedAttributes::ClassMethods to add reflection methods
42
+ module ReflectionMethods
43
+ # Returns reflection for the given association name.
44
+ # This provides compatibility with form builders like ActiveAdmin's has_many.
45
+ # First checks if the attribute is a StoreModel collection type, and if so,
46
+ # returns a reflection for it. Otherwise, delegates to the original implementation
47
+ # for ActiveRecord associations.
48
+ #
49
+ # @param name [Symbol, String] association name
50
+ # @return [StoreModel::ActiveAdminCompatibility::Reflection, nil]
51
+ def reflect_on_association(name)
52
+ # First check if this is a StoreModel attribute
53
+ # Use attribute_types directly to get the type for the given attribute
54
+ type = attribute_types[name.to_s]
55
+
56
+ if type.is_a?(StoreModel::Types::ManyBase) && type.respond_to?(:model_klass) && type.model_klass
57
+ # Return reflection for StoreModel collection attributes
58
+ return StoreModel::ActiveAdminCompatibility::Reflection.new(name.to_sym, type.model_klass)
59
+ end
60
+
61
+ # Not a StoreModel attribute, try to call the original method for ActiveRecord associations
62
+ super
63
+ rescue NoMethodError
64
+ # No super method exists (pure StoreModel class), return nil
65
+ nil
66
+ end
67
+ end
68
+ end
69
+ end
@@ -7,9 +7,9 @@ module StoreModel
7
7
 
8
8
  def assign_parent_to_store_model_relation(attribute)
9
9
  assign_parent_to_singular_store_model(attribute)
10
- return unless attribute.is_a?(Array)
10
+ return if !attribute.is_a?(Array) && !attribute.is_a?(Hash)
11
11
 
12
- attribute.each(&method(:assign_parent_to_singular_store_model))
12
+ (attribute.try(:values) || attribute).each(&method(:assign_parent_to_singular_store_model))
13
13
  end
14
14
 
15
15
  def assign_parent_to_singular_store_model(item)
@@ -8,12 +8,18 @@ require "store_model/nested_attributes"
8
8
  module StoreModel
9
9
  # When included into class configures it to handle JSON column
10
10
  module Model # rubocop:disable Metrics/ModuleLength
11
+ # rubocop:disable Metrics/MethodLength
11
12
  def self.included(base) # :nodoc:
12
13
  base.include ActiveModel::Model
13
14
  base.include ActiveModel::Attributes
14
15
  base.include ActiveRecord::AttributeMethods::BeforeTypeCast
15
16
  base.include ActiveModel::AttributeMethods
16
17
  base.include StoreModel::NestedAttributes
18
+ base.include ActiveModel::Validations::Callbacks
19
+
20
+ if ActiveModel::VERSION::MAJOR >= 8 && ActiveModel::VERSION::MINOR >= 1
21
+ base.include ActiveModel::Attributes::Normalization
22
+ end
17
23
 
18
24
  base.extend StoreModel::Enum
19
25
  base.extend StoreModel::TypeBuilders
@@ -22,6 +28,7 @@ module StoreModel
22
28
 
23
29
  base.extend(ClassMethods)
24
30
  end
31
+ # rubocop:enable Metrics/MethodLength
25
32
 
26
33
  # Class methods for StoreModel::Model
27
34
  module ClassMethods
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "store_model/ext/active_model/attributes"
4
4
  require "store_model/ext/active_record/base"
5
+ require "store_model/ext/active_admin_compatibility"
5
6
 
6
7
  module StoreModel # :nodoc:
7
8
  class Railtie < Rails::Railtie # :nodoc:
@@ -11,6 +12,11 @@ module StoreModel # :nodoc:
11
12
  ActiveModel::Attributes.prepend(Attributes)
12
13
  prepend(Base)
13
14
  end
15
+
16
+ if StoreModel.config.active_admin_compatibility
17
+ StoreModel::Model.prepend(ActiveAdminCompatibility::NewRecordPatch)
18
+ StoreModel::NestedAttributes::ClassMethods.prepend(ActiveAdminCompatibility::ReflectionMethods)
19
+ end
14
20
  end
15
21
  end
16
22
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StoreModel # :nodoc:
4
- VERSION = "4.3.0"
4
+ VERSION = "4.5.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: store_model
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.3.0
4
+ version: 4.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - DmitryTsepelev
@@ -84,6 +84,7 @@ files:
84
84
  - lib/store_model/combine_errors_strategies/merge_hash_error_strategy.rb
85
85
  - lib/store_model/configuration.rb
86
86
  - lib/store_model/enum.rb
87
+ - lib/store_model/ext/active_admin_compatibility.rb
87
88
  - lib/store_model/ext/active_model/attributes.rb
88
89
  - lib/store_model/ext/active_record/base.rb
89
90
  - lib/store_model/ext/parent_assignment.rb