structured_params 0.6.0 → 0.9.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: 66f5daa7a71dd1470ca9f5d8af4d62dd8b0c40227ce6f07812a04206e0083c06
4
- data.tar.gz: 5c9500ee402ecd0c06ab82503ac13b4ed4800cd2a18b87f4b5fecbba692ad4ac
3
+ metadata.gz: 439ee43f03104eab1cab3d22b88f080eb4b3a4b3f995f3207f34b43f1131d850
4
+ data.tar.gz: 6c8a9bbcdc63a3421943e470e0eae9fd8985bf9c492fbfe3d78ac1c1fb91f480
5
5
  SHA512:
6
- metadata.gz: 306948118def08f98c24f460f1e5763e72281a2c31e141ba7db9c376ceea5e1a6ac4ab016a28779f84dfa60ebcf74904b62f66d191507c4066c0f9db055067d6
7
- data.tar.gz: 57d137f7e64e810356f909045a7e250abe82317b8b5574b8b1f2c4db2e2e23476ef48fc792a7cf168cdad646b649261e2bc9548365827645d1b3f5ec327fe8ed
6
+ metadata.gz: 37250d2347c47d83fb46e607498b9e27b0f75c2f1c63d51195b2897b46c9b421bb0612fff0ab8fa2e98bcd2b5ebafc5fee013e7b3717850dfcc7af74b684f214
7
+ data.tar.gz: cfcbce547b38e7680a94804ed0df7112c0f03218d2998b4e48917f702353942eaf5cd5c854fe43cf9ada08a2546a06e96038ea9ef707caec210cb2e1c2b11272
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.0] - 2026-03-18
4
+
5
+ ## What's Changed
6
+ * Add form objects and specs by @Syati in https://github.com/Syati/structured_params/pull/12
7
+
8
+
9
+ **Full Changelog**: https://github.com/Syati/structured_params/compare/v0.6.0...v0.9.0
10
+
3
11
  ## [0.6.0] - 2026-02-28
4
12
 
5
13
  ## What's Changed
@@ -4,13 +4,48 @@
4
4
  module StructuredParams
5
5
  # Parameter model that supports structured objects and arrays
6
6
  #
7
- # Usage example:
8
- # class UserParameter < StructuredParams::Params
7
+ # This class can be used in two ways:
8
+ # 1. Strong Parameters validation (API requests)
9
+ # 2. Form objects (View integration with form_with/form_for)
10
+ #
11
+ # Strong Parameters example (API):
12
+ # class UserParams < StructuredParams::Params
9
13
  # attribute :name, :string
10
- # attribute :address, :object, value_class: AddressParameter
11
- # attribute :hobbies, :array, value_class: HobbyParameter
14
+ # attribute :address, :object, value_class: AddressParams
15
+ # attribute :hobbies, :array, value_class: HobbyParams
12
16
  # attribute :tags, :array, value_type: :string
13
17
  # end
18
+ #
19
+ # # In controller:
20
+ # user_params = UserParams.new(params)
21
+ # if user_params.valid?
22
+ # User.create!(user_params.attributes)
23
+ # else
24
+ # render json: { errors: user_params.errors }
25
+ # end
26
+ #
27
+ # Form object example (View integration):
28
+ # class UserRegistrationForm < StructuredParams::Params
29
+ # attribute :name, :string
30
+ # attribute :email, :string
31
+ # validates :name, presence: true
32
+ # validates :email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
33
+ # end
34
+ #
35
+ # # In controller:
36
+ # @form = UserRegistrationForm.new(UserRegistrationForm.permit(params))
37
+ # if @form.valid?
38
+ # User.create!(@form.attributes)
39
+ # redirect_to user_path
40
+ # else
41
+ # render :new
42
+ # end
43
+ #
44
+ # # In view:
45
+ # <%= form_with model: @form, url: users_path do |f| %>
46
+ # <%= f.text_field :name %>
47
+ # <%= f.text_field :email %>
48
+ # <% end %>
14
49
  class Params
15
50
  include ActiveModel::Model
16
51
  include ActiveModel::Attributes
@@ -18,7 +53,27 @@ module StructuredParams
18
53
  # @rbs @errors: ::StructuredParams::Errors?
19
54
 
20
55
  class << self
21
- # @rbs @structured_attributes: Hash[Symbol, singleton(::StructuredParams::Params)]?
56
+ # @rbs self.@structured_attributes: Hash[Symbol, singleton(::StructuredParams::Params)]?
57
+ # @rbs self.@model_name: ::ActiveModel::Name?
58
+
59
+ # Override model_name for form helpers
60
+ # By default, removes "Parameters", "Parameter", or "Form" suffix from class name
61
+ # This allows the class to work seamlessly with Rails form helpers
62
+ #
63
+ # Example:
64
+ # UserRegistrationForm.model_name.name # => "UserRegistration"
65
+ # UserRegistrationForm.model_name.param_key # => "user_registration"
66
+ # UserParameters.model_name.name # => "User"
67
+ # Admin::UserForm.model_name.name # => "Admin::User"
68
+ #: () -> ::ActiveModel::Name
69
+ def model_name
70
+ @model_name ||= begin
71
+ namespace = module_parents.detect { |n| n.respond_to?(:use_relative_model_naming?) }
72
+ # Remove suffix from the full class name (preserving namespace)
73
+ name_without_suffix = name.sub(/(Parameters?|Form)$/, '')
74
+ ActiveModel::Name.new(self, namespace, name_without_suffix)
75
+ end
76
+ end
22
77
 
23
78
  # Generate permitted parameter structure for Strong Parameters
24
79
  #: () -> Array[untyped]
@@ -34,6 +89,28 @@ module StructuredParams
34
89
  end
35
90
  end
36
91
 
92
+ # Permit parameters with optional require
93
+ #
94
+ # For Form Objects (with require):
95
+ # UserRegistrationForm.permit(params)
96
+ # # equivalent to:
97
+ # params.require(:user_registration).permit(*UserRegistrationForm.permit_attribute_names)
98
+ #
99
+ # For API requests (without require):
100
+ # UserParams.permit(params, require: false)
101
+ # # equivalent to:
102
+ # params.permit(*UserParams.permit_attribute_names)
103
+ #
104
+ #: (ActionController::Parameters params, ?require: bool) -> ActionController::Parameters
105
+ def permit(params, require: true)
106
+ if require
107
+ key = model_name.param_key.to_sym
108
+ params.require(key).permit(*permit_attribute_names)
109
+ else
110
+ params.permit(*permit_attribute_names)
111
+ end
112
+ end
113
+
37
114
  # Get structured attributes and their classes
38
115
  #: () -> Hash[Symbol, singleton(::StructuredParams::Params)]
39
116
  def structured_attributes
@@ -72,6 +149,32 @@ module StructuredParams
72
149
  @errors ||= Errors.new(self)
73
150
  end
74
151
 
152
+ # ========================================
153
+ # Form object support methods
154
+ # These methods enable integration with Rails form helpers (form_with, form_for)
155
+ # ========================================
156
+
157
+ # Indicates whether the form object has been persisted to database
158
+ # Always returns false for parameter/form objects
159
+ #: () -> bool
160
+ def persisted?
161
+ false
162
+ end
163
+
164
+ # Returns the primary key value for the model
165
+ # Always returns nil for parameter/form objects
166
+ #: () -> nil
167
+ def to_key
168
+ nil
169
+ end
170
+
171
+ # Returns self for form helpers
172
+ # Required by Rails form helpers to get the model object
173
+ #: () -> self
174
+ def to_model
175
+ self
176
+ end
177
+
75
178
  # Convert structured objects to Hash and get attributes
76
179
  #: (?symbolize: false, ?compact_mode: :none | :nil_only | :all_blank) -> Hash[String, untyped]
77
180
  #: (?symbolize: true, ?compact_mode: :none | :nil_only | :all_blank) -> Hash[Symbol, untyped]
@@ -102,7 +205,7 @@ module StructuredParams
102
205
  def process_input_parameters(params)
103
206
  case params
104
207
  when ActionController::Parameters
105
- params.permit(self.class.permit_attribute_names).to_h
208
+ self.class.permit(params, require: false).to_h
106
209
  when Hash
107
210
  # ActiveModel::Attributes can handle both symbol and string keys
108
211
  params
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module StructuredParams
5
- VERSION = '0.6.0' #: string
5
+ VERSION = '0.9.0' #: string
6
6
  end
@@ -3,13 +3,48 @@
3
3
  module StructuredParams
4
4
  # Parameter model that supports structured objects and arrays
5
5
  #
6
- # Usage example:
7
- # class UserParameter < StructuredParams::Params
6
+ # This class can be used in two ways:
7
+ # 1. Strong Parameters validation (API requests)
8
+ # 2. Form objects (View integration with form_with/form_for)
9
+ #
10
+ # Strong Parameters example (API):
11
+ # class UserParams < StructuredParams::Params
8
12
  # attribute :name, :string
9
- # attribute :address, :object, value_class: AddressParameter
10
- # attribute :hobbies, :array, value_class: HobbyParameter
13
+ # attribute :address, :object, value_class: AddressParams
14
+ # attribute :hobbies, :array, value_class: HobbyParams
11
15
  # attribute :tags, :array, value_type: :string
12
16
  # end
17
+ #
18
+ # # In controller:
19
+ # user_params = UserParams.new(params)
20
+ # if user_params.valid?
21
+ # User.create!(user_params.attributes)
22
+ # else
23
+ # render json: { errors: user_params.errors }
24
+ # end
25
+ #
26
+ # Form object example (View integration):
27
+ # class UserRegistrationForm < StructuredParams::Params
28
+ # attribute :name, :string
29
+ # attribute :email, :string
30
+ # validates :name, presence: true
31
+ # validates :email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
32
+ # end
33
+ #
34
+ # # In controller:
35
+ # @form = UserRegistrationForm.new(UserRegistrationForm.permit(params))
36
+ # if @form.valid?
37
+ # User.create!(@form.attributes)
38
+ # redirect_to user_path
39
+ # else
40
+ # render :new
41
+ # end
42
+ #
43
+ # # In view:
44
+ # <%= form_with model: @form, url: users_path do |f| %>
45
+ # <%= f.text_field :name %>
46
+ # <%= f.text_field :email %>
47
+ # <% end %>
13
48
  class Params
14
49
  include ActiveModel::Model
15
50
 
@@ -19,10 +54,39 @@ module StructuredParams
19
54
 
20
55
  self.@structured_attributes: Hash[Symbol, singleton(::StructuredParams::Params)]?
21
56
 
57
+ self.@model_name: ::ActiveModel::Name?
58
+
59
+ # Override model_name for form helpers
60
+ # By default, removes "Parameters", "Parameter", or "Form" suffix from class name
61
+ # This allows the class to work seamlessly with Rails form helpers
62
+ #
63
+ # Example:
64
+ # UserRegistrationForm.model_name.name # => "UserRegistration"
65
+ # UserRegistrationForm.model_name.param_key # => "user_registration"
66
+ # UserParameters.model_name.name # => "User"
67
+ # Admin::UserForm.model_name.name # => "Admin::User"
68
+ # : () -> ::ActiveModel::Name
69
+ def self.model_name: () -> ::ActiveModel::Name
70
+
22
71
  # Generate permitted parameter structure for Strong Parameters
23
72
  # : () -> Array[untyped]
24
73
  def self.permit_attribute_names: () -> Array[untyped]
25
74
 
75
+ # Permit parameters with optional require
76
+ #
77
+ # For Form Objects (with require):
78
+ # UserRegistrationForm.permit(params)
79
+ # # equivalent to:
80
+ # params.require(:user_registration).permit(*UserRegistrationForm.permit_attribute_names)
81
+ #
82
+ # For API requests (without require):
83
+ # UserParams.permit(params, require: false)
84
+ # # equivalent to:
85
+ # params.permit(*UserParams.permit_attribute_names)
86
+ #
87
+ # : (ActionController::Parameters params, ?require: bool) -> ActionController::Parameters
88
+ def self.permit: (ActionController::Parameters params, ?require: bool) -> ActionController::Parameters
89
+
26
90
  # Get structured attributes and their classes
27
91
  # : () -> Hash[Symbol, singleton(::StructuredParams::Params)]
28
92
  def self.structured_attributes: () -> Hash[Symbol, singleton(::StructuredParams::Params)]
@@ -37,6 +101,21 @@ module StructuredParams
37
101
  # : () -> ::StructuredParams::Errors
38
102
  def errors: () -> ::StructuredParams::Errors
39
103
 
104
+ # Indicates whether the form object has been persisted to database
105
+ # Always returns false for parameter/form objects
106
+ # : () -> bool
107
+ def persisted?: () -> bool
108
+
109
+ # Returns the primary key value for the model
110
+ # Always returns nil for parameter/form objects
111
+ # : () -> nil
112
+ def to_key: () -> nil
113
+
114
+ # Returns self for form helpers
115
+ # Required by Rails form helpers to get the model object
116
+ # : () -> self
117
+ def to_model: () -> self
118
+
40
119
  # Convert structured objects to Hash and get attributes
41
120
  # : (?symbolize: false, ?compact_mode: :none | :nil_only | :all_blank) -> Hash[String, untyped]
42
121
  # : (?symbolize: true, ?compact_mode: :none | :nil_only | :all_blank) -> Hash[Symbol, untyped]
@@ -54,16 +133,12 @@ module StructuredParams
54
133
  def validate_structured_parameters: () -> void
55
134
 
56
135
  # Validate structured arrays
57
- # @rbs attr_name: Symbol
58
- # @rbs array_value: Array[untyped]
59
- # @rbs return: void
60
- def validate_structured_array: (Symbol attr_name, Array[untyped] array_value) -> void
136
+ # : (Symbol, Array[untyped]) -> void
137
+ def validate_structured_array: (Symbol, Array[untyped]) -> void
61
138
 
62
139
  # Validate structured objects
63
- # @rbs attr_name: Symbol
64
- # @rbs object_value: ::StructuredParams::Params
65
- # @rbs return: void
66
- def validate_structured_object: (Symbol attr_name, ::StructuredParams::Params object_value) -> void
140
+ # : (Symbol, StructuredParams::Params) -> void
141
+ def validate_structured_object: (Symbol, StructuredParams::Params) -> void
67
142
 
68
143
  # Format error path using dot notation (always consistent)
69
144
  # : (Symbol, Integer?) -> String
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: structured_params
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mizuki Yamamoto