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 +4 -4
- data/CHANGELOG.md +8 -0
- data/lib/structured_params/params.rb +109 -6
- data/lib/structured_params/version.rb +1 -1
- data/sig/structured_params/params.rbs +87 -12
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 439ee43f03104eab1cab3d22b88f080eb4b3a4b3f995f3207f34b43f1131d850
|
|
4
|
+
data.tar.gz: 6c8a9bbcdc63a3421943e470e0eae9fd8985bf9c492fbfe3d78ac1c1fb91f480
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
#
|
|
8
|
-
#
|
|
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:
|
|
11
|
-
# attribute :hobbies, :array, value_class:
|
|
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
|
|
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
|
-
|
|
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
|
|
@@ -3,13 +3,48 @@
|
|
|
3
3
|
module StructuredParams
|
|
4
4
|
# Parameter model that supports structured objects and arrays
|
|
5
5
|
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
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:
|
|
10
|
-
# attribute :hobbies, :array, value_class:
|
|
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
|
-
#
|
|
58
|
-
|
|
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
|
-
#
|
|
64
|
-
|
|
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
|