action_form 0.3.0 → 0.4.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/README.md +389 -0
 - data/lib/action_form/elements_dsl.rb +17 -0
 - data/lib/action_form/subform.rb +7 -0
 - data/lib/action_form/subforms_collection.rb +9 -3
 - data/lib/action_form/version.rb +1 -1
 - 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: a83d578e9d0fbf58ccb568473d8a94e1ccb087df4b8f8e5ee2871f2a4689c7b0
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: e155e0fada05ece59a1e501fe6d6e52ca0cbd652292f0b243e7e59999760562d
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 91b6b047b9ac52d7e1d9162ed4b555456466fa7f59e94d54242492f2e515ad352f145aa179027d51753ec78ed1f12150628e23ab156a56de29b29998e1ae968a
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: e64a656d32e8d9ddc91d37d4913c30c513e37854d8f77e368a0acf27e66a1a12a579b8c81bdd4ffd79f4c1ff508850834a256ad93728d762963c8bd317a9c612
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -8,6 +8,7 @@ This library allows you to build complex forms in Ruby with a simple DSL. It pro 
     | 
|
| 
       8 
8 
     | 
    
         | 
| 
       9 
9 
     | 
    
         
             
            - A clean, declarative syntax for defining form fields and validations
         
     | 
| 
       10 
10 
     | 
    
         
             
            - Support for nested forms
         
     | 
| 
      
 11 
     | 
    
         
            +
            - Custom parameter validation with the `params` method
         
     | 
| 
       11 
12 
     | 
    
         
             
            - Automatic form rendering with customizable HTML/CSS
         
     | 
| 
       12 
13 
     | 
    
         
             
            - Built-in error handling and validation
         
     | 
| 
       13 
14 
     | 
    
         
             
            - Integration with Rails and other Ruby web frameworks
         
     | 
| 
         @@ -61,6 +62,7 @@ ActionForm is built around a modular architecture that separates form definition 
     | 
|
| 
       61 
62 
     | 
    
         | 
| 
       62 
63 
     | 
    
         
             
            - **Declarative DSL**: Define forms with simple, readable syntax
         
     | 
| 
       63 
64 
     | 
    
         
             
            - **Nested Forms**: Support for complex nested structures with `subform` and `many`
         
     | 
| 
      
 65 
     | 
    
         
            +
            - **Custom Parameter Validation**: Use the `params` method to add custom validation logic and schema modifications
         
     | 
| 
       64 
66 
     | 
    
         
             
            - **Dynamic Collections**: JavaScript-powered add/remove functionality for many relationships
         
     | 
| 
       65 
67 
     | 
    
         
             
            - **Flexible Rendering**: Each element can be configured with custom input types, labels, and HTML attributes
         
     | 
| 
       66 
68 
     | 
    
         
             
            - **Error Integration**: Built-in support for displaying validation errors
         
     | 
| 
         @@ -86,6 +88,7 @@ ActionForm follows a bidirectional data flow pattern that handles both form disp 
     | 
|
| 
       86 
88 
     | 
    
         
             
            #### **Key Benefits:**
         
     | 
| 
       87 
89 
     | 
    
         
             
            - **Single Source of Truth**: The same form definition handles both displaying existing data and processing new data
         
     | 
| 
       88 
90 
     | 
    
         
             
            - **Automatic Parameter Handling**: [EasyParams](https://github.com/andriy-baran/easy_params) classes are automatically generated to mirror your form structure
         
     | 
| 
      
 91 
     | 
    
         
            +
            - **Custom Parameter Validation**: Use the `params` method to add custom validation logic and schema modifications
         
     | 
| 
       89 
92 
     | 
    
         
             
            - **Error Integration**: Failed validations can re-render the form with submitted data and error messages
         
     | 
| 
       90 
93 
     | 
    
         
             
            - **Nested Support**: Both phases support complex nested structures through `subform` and `many` relationships
         
     | 
| 
       91 
94 
     | 
    
         | 
| 
         @@ -250,6 +253,374 @@ class UserForm < ActionForm::Base 
     | 
|
| 
       250 
253 
     | 
    
         
             
            end
         
     | 
| 
       251 
254 
     | 
    
         
             
            ```
         
     | 
| 
       252 
255 
     | 
    
         | 
| 
      
 256 
     | 
    
         
            +
            ### Custom Parameter Validation
         
     | 
| 
      
 257 
     | 
    
         
            +
             
     | 
| 
      
 258 
     | 
    
         
            +
            ActionForm provides a `params` method that allows you to add custom validation logic and schema modifications to your form's parameter handling. This is particularly useful for complex validation rules that depend on context or require cross-field validation.
         
     | 
| 
      
 259 
     | 
    
         
            +
             
     | 
| 
      
 260 
     | 
    
         
            +
            #### **Basic Usage**
         
     | 
| 
      
 261 
     | 
    
         
            +
             
     | 
| 
      
 262 
     | 
    
         
            +
            Use the `params` method to define custom validation logic:
         
     | 
| 
      
 263 
     | 
    
         
            +
             
     | 
| 
      
 264 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 265 
     | 
    
         
            +
            class UserForm < ActionForm::Base
         
     | 
| 
      
 266 
     | 
    
         
            +
              element :email do
         
     | 
| 
      
 267 
     | 
    
         
            +
                input type: :email
         
     | 
| 
      
 268 
     | 
    
         
            +
                output type: :string, presence: true
         
     | 
| 
      
 269 
     | 
    
         
            +
              end
         
     | 
| 
      
 270 
     | 
    
         
            +
             
     | 
| 
      
 271 
     | 
    
         
            +
              element :password do
         
     | 
| 
      
 272 
     | 
    
         
            +
                input type: :password
         
     | 
| 
      
 273 
     | 
    
         
            +
                output type: :string
         
     | 
| 
      
 274 
     | 
    
         
            +
              end
         
     | 
| 
      
 275 
     | 
    
         
            +
             
     | 
| 
      
 276 
     | 
    
         
            +
              element :password_confirmation do
         
     | 
| 
      
 277 
     | 
    
         
            +
                input type: :password
         
     | 
| 
      
 278 
     | 
    
         
            +
                output type: :string
         
     | 
| 
      
 279 
     | 
    
         
            +
              end
         
     | 
| 
      
 280 
     | 
    
         
            +
             
     | 
| 
      
 281 
     | 
    
         
            +
              # Custom parameter validation
         
     | 
| 
      
 282 
     | 
    
         
            +
              params do
         
     | 
| 
      
 283 
     | 
    
         
            +
                validates :password, presence: true
         
     | 
| 
      
 284 
     | 
    
         
            +
                validates :password_confirmation, presence: true
         
     | 
| 
      
 285 
     | 
    
         
            +
                validates :password, confirmation: true
         
     | 
| 
      
 286 
     | 
    
         
            +
              end
         
     | 
| 
      
 287 
     | 
    
         
            +
            end
         
     | 
| 
      
 288 
     | 
    
         
            +
            ```
         
     | 
| 
      
 289 
     | 
    
         
            +
             
     | 
| 
      
 290 
     | 
    
         
            +
            #### **Conditional Validation**
         
     | 
| 
      
 291 
     | 
    
         
            +
             
     | 
| 
      
 292 
     | 
    
         
            +
            You can add conditional validation logic based on context:
         
     | 
| 
      
 293 
     | 
    
         
            +
             
     | 
| 
      
 294 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 295 
     | 
    
         
            +
            class UserForm < ActionForm::Base
         
     | 
| 
      
 296 
     | 
    
         
            +
              element :email do
         
     | 
| 
      
 297 
     | 
    
         
            +
                input type: :email
         
     | 
| 
      
 298 
     | 
    
         
            +
                output type: :string, presence: true
         
     | 
| 
      
 299 
     | 
    
         
            +
              end
         
     | 
| 
      
 300 
     | 
    
         
            +
             
     | 
| 
      
 301 
     | 
    
         
            +
              element :password do
         
     | 
| 
      
 302 
     | 
    
         
            +
                input type: :password
         
     | 
| 
      
 303 
     | 
    
         
            +
                output type: :string
         
     | 
| 
      
 304 
     | 
    
         
            +
              end
         
     | 
| 
      
 305 
     | 
    
         
            +
             
     | 
| 
      
 306 
     | 
    
         
            +
              # Conditional validation based on external context
         
     | 
| 
      
 307 
     | 
    
         
            +
              params do
         
     | 
| 
      
 308 
     | 
    
         
            +
                secure_mode = true  # This could come from configuration or request context
         
     | 
| 
      
 309 
     | 
    
         
            +
             
     | 
| 
      
 310 
     | 
    
         
            +
                validates :password, presence: true, if: -> { secure_mode }
         
     | 
| 
      
 311 
     | 
    
         
            +
                validates :password, length: { minimum: 8 }, if: -> { secure_mode }
         
     | 
| 
      
 312 
     | 
    
         
            +
              end
         
     | 
| 
      
 313 
     | 
    
         
            +
            end
         
     | 
| 
      
 314 
     | 
    
         
            +
            ```
         
     | 
| 
      
 315 
     | 
    
         
            +
             
     | 
| 
      
 316 
     | 
    
         
            +
            #### **Nested Form Validation**
         
     | 
| 
      
 317 
     | 
    
         
            +
             
     | 
| 
      
 318 
     | 
    
         
            +
            The `params` method also supports validation for nested forms using schema blocks:
         
     | 
| 
      
 319 
     | 
    
         
            +
             
     | 
| 
      
 320 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 321 
     | 
    
         
            +
            class UserForm < ActionForm::Base
         
     | 
| 
      
 322 
     | 
    
         
            +
              element :email do
         
     | 
| 
      
 323 
     | 
    
         
            +
                input type: :email
         
     | 
| 
      
 324 
     | 
    
         
            +
                output type: :string, presence: true
         
     | 
| 
      
 325 
     | 
    
         
            +
              end
         
     | 
| 
      
 326 
     | 
    
         
            +
             
     | 
| 
      
 327 
     | 
    
         
            +
              subform :profile, default: {} do
         
     | 
| 
      
 328 
     | 
    
         
            +
                element :name do
         
     | 
| 
      
 329 
     | 
    
         
            +
                  input type: :text
         
     | 
| 
      
 330 
     | 
    
         
            +
                  output type: :string
         
     | 
| 
      
 331 
     | 
    
         
            +
                end
         
     | 
| 
      
 332 
     | 
    
         
            +
              end
         
     | 
| 
      
 333 
     | 
    
         
            +
             
     | 
| 
      
 334 
     | 
    
         
            +
              many :addresses, default: [{}] do
         
     | 
| 
      
 335 
     | 
    
         
            +
                subform do
         
     | 
| 
      
 336 
     | 
    
         
            +
                  element :street do
         
     | 
| 
      
 337 
     | 
    
         
            +
                    input type: :text
         
     | 
| 
      
 338 
     | 
    
         
            +
                    output type: :string
         
     | 
| 
      
 339 
     | 
    
         
            +
                  end
         
     | 
| 
      
 340 
     | 
    
         
            +
             
     | 
| 
      
 341 
     | 
    
         
            +
                  element :city do
         
     | 
| 
      
 342 
     | 
    
         
            +
                    input type: :text
         
     | 
| 
      
 343 
     | 
    
         
            +
                    output type: :string
         
     | 
| 
      
 344 
     | 
    
         
            +
                  end
         
     | 
| 
      
 345 
     | 
    
         
            +
                end
         
     | 
| 
      
 346 
     | 
    
         
            +
              end
         
     | 
| 
      
 347 
     | 
    
         
            +
             
     | 
| 
      
 348 
     | 
    
         
            +
              params do
         
     | 
| 
      
 349 
     | 
    
         
            +
                # Validate nested subform
         
     | 
| 
      
 350 
     | 
    
         
            +
                profile_attributes_schema do
         
     | 
| 
      
 351 
     | 
    
         
            +
                  validates :name, presence: true
         
     | 
| 
      
 352 
     | 
    
         
            +
                end
         
     | 
| 
      
 353 
     | 
    
         
            +
             
     | 
| 
      
 354 
     | 
    
         
            +
                # Validate nested collection
         
     | 
| 
      
 355 
     | 
    
         
            +
                addresses_attributes_schema do
         
     | 
| 
      
 356 
     | 
    
         
            +
                  validates :street, presence: true
         
     | 
| 
      
 357 
     | 
    
         
            +
                  validates :city, presence: true
         
     | 
| 
      
 358 
     | 
    
         
            +
                end
         
     | 
| 
      
 359 
     | 
    
         
            +
              end
         
     | 
| 
      
 360 
     | 
    
         
            +
            end
         
     | 
| 
      
 361 
     | 
    
         
            +
            ```
         
     | 
| 
      
 362 
     | 
    
         
            +
             
     | 
| 
      
 363 
     | 
    
         
            +
            #### **Dynamic Form Classes**
         
     | 
| 
      
 364 
     | 
    
         
            +
             
     | 
| 
      
 365 
     | 
    
         
            +
            You can create dynamic form classes with different validation rules:
         
     | 
| 
      
 366 
     | 
    
         
            +
             
     | 
| 
      
 367 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 368 
     | 
    
         
            +
            class BaseUserForm < ActionForm::Base
         
     | 
| 
      
 369 
     | 
    
         
            +
              element :email do
         
     | 
| 
      
 370 
     | 
    
         
            +
                input type: :email
         
     | 
| 
      
 371 
     | 
    
         
            +
                output type: :string, presence: true
         
     | 
| 
      
 372 
     | 
    
         
            +
              end
         
     | 
| 
      
 373 
     | 
    
         
            +
             
     | 
| 
      
 374 
     | 
    
         
            +
              element :password do
         
     | 
| 
      
 375 
     | 
    
         
            +
                input type: :password
         
     | 
| 
      
 376 
     | 
    
         
            +
                output type: :string
         
     | 
| 
      
 377 
     | 
    
         
            +
              end
         
     | 
| 
      
 378 
     | 
    
         
            +
            end
         
     | 
| 
      
 379 
     | 
    
         
            +
             
     | 
| 
      
 380 
     | 
    
         
            +
            # Create a secure version with additional validation
         
     | 
| 
      
 381 
     | 
    
         
            +
            SecureUserForm = Class.new(BaseUserForm)
         
     | 
| 
      
 382 
     | 
    
         
            +
            SecureUserForm.params do
         
     | 
| 
      
 383 
     | 
    
         
            +
              validates :password, presence: true, length: { minimum: 8 }
         
     | 
| 
      
 384 
     | 
    
         
            +
              validates :password, format: { with: /\A(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/ }
         
     | 
| 
      
 385 
     | 
    
         
            +
            end
         
     | 
| 
      
 386 
     | 
    
         
            +
             
     | 
| 
      
 387 
     | 
    
         
            +
            # Create a basic version with minimal validation
         
     | 
| 
      
 388 
     | 
    
         
            +
            BasicUserForm = Class.new(BaseUserForm)
         
     | 
| 
      
 389 
     | 
    
         
            +
            BasicUserForm.params do
         
     | 
| 
      
 390 
     | 
    
         
            +
              validates :password, presence: true
         
     | 
| 
      
 391 
     | 
    
         
            +
            end
         
     | 
| 
      
 392 
     | 
    
         
            +
            ```
         
     | 
| 
      
 393 
     | 
    
         
            +
             
     | 
| 
      
 394 
     | 
    
         
            +
            #### **Integration with Controllers**
         
     | 
| 
      
 395 
     | 
    
         
            +
             
     | 
| 
      
 396 
     | 
    
         
            +
            The custom parameter validation integrates seamlessly with your controllers:
         
     | 
| 
      
 397 
     | 
    
         
            +
             
     | 
| 
      
 398 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 399 
     | 
    
         
            +
            class UsersController < ApplicationController
         
     | 
| 
      
 400 
     | 
    
         
            +
              def create
         
     | 
| 
      
 401 
     | 
    
         
            +
                user_params = UserForm.params_definition.new(params)
         
     | 
| 
      
 402 
     | 
    
         
            +
             
     | 
| 
      
 403 
     | 
    
         
            +
                if user_params.valid?
         
     | 
| 
      
 404 
     | 
    
         
            +
                  @user = User.create!(user_params.to_h)
         
     | 
| 
      
 405 
     | 
    
         
            +
                  redirect_to @user
         
     | 
| 
      
 406 
     | 
    
         
            +
                else
         
     | 
| 
      
 407 
     | 
    
         
            +
                  @form = @form.with_params(user_params)
         
     | 
| 
      
 408 
     | 
    
         
            +
                  render :new
         
     | 
| 
      
 409 
     | 
    
         
            +
                end
         
     | 
| 
      
 410 
     | 
    
         
            +
              end
         
     | 
| 
      
 411 
     | 
    
         
            +
            end
         
     | 
| 
      
 412 
     | 
    
         
            +
            ```
         
     | 
| 
      
 413 
     | 
    
         
            +
             
     | 
| 
      
 414 
     | 
    
         
            +
            The `params` method provides a powerful way to extend ActionForm's parameter handling with custom validation logic while maintaining the declarative nature of form definition.
         
     | 
| 
      
 415 
     | 
    
         
            +
             
     | 
| 
      
 416 
     | 
    
         
            +
            ### Modifying Element Definitions
         
     | 
| 
      
 417 
     | 
    
         
            +
             
     | 
| 
      
 418 
     | 
    
         
            +
            ActionForm allows you to modify existing element, subform, and `many` definitions after they have been declared. This feature enables you to extend or customize form definitions without altering the original class structure, making it perfect for conditional modifications, inheritance patterns, and dynamic form customization.
         
     | 
| 
      
 419 
     | 
    
         
            +
             
     | 
| 
      
 420 
     | 
    
         
            +
            #### **Modifying Elements**
         
     | 
| 
      
 421 
     | 
    
         
            +
             
     | 
| 
      
 422 
     | 
    
         
            +
            Use the `{element_name}_element` method to modify an existing element definition:
         
     | 
| 
      
 423 
     | 
    
         
            +
             
     | 
| 
      
 424 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 425 
     | 
    
         
            +
            class UserForm < ActionForm::Base
         
     | 
| 
      
 426 
     | 
    
         
            +
              element :email do
         
     | 
| 
      
 427 
     | 
    
         
            +
                input type: :email
         
     | 
| 
      
 428 
     | 
    
         
            +
                output type: :string
         
     | 
| 
      
 429 
     | 
    
         
            +
              end
         
     | 
| 
      
 430 
     | 
    
         
            +
             
     | 
| 
      
 431 
     | 
    
         
            +
              element :password do
         
     | 
| 
      
 432 
     | 
    
         
            +
                input type: :password
         
     | 
| 
      
 433 
     | 
    
         
            +
                output type: :string
         
     | 
| 
      
 434 
     | 
    
         
            +
              end
         
     | 
| 
      
 435 
     | 
    
         
            +
            end
         
     | 
| 
      
 436 
     | 
    
         
            +
             
     | 
| 
      
 437 
     | 
    
         
            +
            # Modify existing element definitions
         
     | 
| 
      
 438 
     | 
    
         
            +
            UserForm.email_element do
         
     | 
| 
      
 439 
     | 
    
         
            +
              output type: :string, presence: true, format: /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
         
     | 
| 
      
 440 
     | 
    
         
            +
            end
         
     | 
| 
      
 441 
     | 
    
         
            +
             
     | 
| 
      
 442 
     | 
    
         
            +
            UserForm.password_element do
         
     | 
| 
      
 443 
     | 
    
         
            +
              output type: :string, presence: true, length: { minimum: 8 }
         
     | 
| 
      
 444 
     | 
    
         
            +
            end
         
     | 
| 
      
 445 
     | 
    
         
            +
            ```
         
     | 
| 
      
 446 
     | 
    
         
            +
             
     | 
| 
      
 447 
     | 
    
         
            +
            #### **Modifying Subforms**
         
     | 
| 
      
 448 
     | 
    
         
            +
             
     | 
| 
      
 449 
     | 
    
         
            +
            Use the `{subform_name}_subform` method to modify an existing subform definition:
         
     | 
| 
      
 450 
     | 
    
         
            +
             
     | 
| 
      
 451 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 452 
     | 
    
         
            +
            class UserForm < ActionForm::Base
         
     | 
| 
      
 453 
     | 
    
         
            +
              subform :profile do
         
     | 
| 
      
 454 
     | 
    
         
            +
                element :bio do
         
     | 
| 
      
 455 
     | 
    
         
            +
                  input type: :textarea
         
     | 
| 
      
 456 
     | 
    
         
            +
                  output type: :string
         
     | 
| 
      
 457 
     | 
    
         
            +
                end
         
     | 
| 
      
 458 
     | 
    
         
            +
              end
         
     | 
| 
      
 459 
     | 
    
         
            +
            end
         
     | 
| 
      
 460 
     | 
    
         
            +
             
     | 
| 
      
 461 
     | 
    
         
            +
            # Modify the subform to add validation or change defaults
         
     | 
| 
      
 462 
     | 
    
         
            +
            UserForm.profile_subform default: {} do
         
     | 
| 
      
 463 
     | 
    
         
            +
              bio_element do
         
     | 
| 
      
 464 
     | 
    
         
            +
                output type: :string, presence: true
         
     | 
| 
      
 465 
     | 
    
         
            +
              end
         
     | 
| 
      
 466 
     | 
    
         
            +
             
     | 
| 
      
 467 
     | 
    
         
            +
              # You can also add new elements
         
     | 
| 
      
 468 
     | 
    
         
            +
              element :avatar do
         
     | 
| 
      
 469 
     | 
    
         
            +
                input type: :file
         
     | 
| 
      
 470 
     | 
    
         
            +
                output type: :string
         
     | 
| 
      
 471 
     | 
    
         
            +
              end
         
     | 
| 
      
 472 
     | 
    
         
            +
            end
         
     | 
| 
      
 473 
     | 
    
         
            +
            ```
         
     | 
| 
      
 474 
     | 
    
         
            +
             
     | 
| 
      
 475 
     | 
    
         
            +
            #### **Modifying Many Relationships**
         
     | 
| 
      
 476 
     | 
    
         
            +
             
     | 
| 
      
 477 
     | 
    
         
            +
            Use the `{many_name}_subforms` method to modify an existing `many` definition:
         
     | 
| 
      
 478 
     | 
    
         
            +
             
     | 
| 
      
 479 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 480 
     | 
    
         
            +
            class OrderForm < ActionForm::Base
         
     | 
| 
      
 481 
     | 
    
         
            +
              many :items do
         
     | 
| 
      
 482 
     | 
    
         
            +
                subform do
         
     | 
| 
      
 483 
     | 
    
         
            +
                  element :name do
         
     | 
| 
      
 484 
     | 
    
         
            +
                    input type: :text
         
     | 
| 
      
 485 
     | 
    
         
            +
                    output type: :string
         
     | 
| 
      
 486 
     | 
    
         
            +
                  end
         
     | 
| 
      
 487 
     | 
    
         
            +
             
     | 
| 
      
 488 
     | 
    
         
            +
                  element :quantity do
         
     | 
| 
      
 489 
     | 
    
         
            +
                    input type: :number
         
     | 
| 
      
 490 
     | 
    
         
            +
                    output type: :integer
         
     | 
| 
      
 491 
     | 
    
         
            +
                  end
         
     | 
| 
      
 492 
     | 
    
         
            +
                end
         
     | 
| 
      
 493 
     | 
    
         
            +
              end
         
     | 
| 
      
 494 
     | 
    
         
            +
            end
         
     | 
| 
      
 495 
     | 
    
         
            +
             
     | 
| 
      
 496 
     | 
    
         
            +
            # Modify the many relationship to add validation or change defaults
         
     | 
| 
      
 497 
     | 
    
         
            +
            OrderForm.items_subforms default: [{}] do
         
     | 
| 
      
 498 
     | 
    
         
            +
              subform do
         
     | 
| 
      
 499 
     | 
    
         
            +
                name_element do
         
     | 
| 
      
 500 
     | 
    
         
            +
                  output type: :string, presence: true
         
     | 
| 
      
 501 
     | 
    
         
            +
                end
         
     | 
| 
      
 502 
     | 
    
         
            +
             
     | 
| 
      
 503 
     | 
    
         
            +
                quantity_element do
         
     | 
| 
      
 504 
     | 
    
         
            +
                  output type: :integer, presence: true, inclusion: { in: 1..100 }
         
     | 
| 
      
 505 
     | 
    
         
            +
                end
         
     | 
| 
      
 506 
     | 
    
         
            +
             
     | 
| 
      
 507 
     | 
    
         
            +
                # Add new elements to existing many subforms
         
     | 
| 
      
 508 
     | 
    
         
            +
                element :price do
         
     | 
| 
      
 509 
     | 
    
         
            +
                  input type: :number
         
     | 
| 
      
 510 
     | 
    
         
            +
                  output type: :float, presence: true
         
     | 
| 
      
 511 
     | 
    
         
            +
                end
         
     | 
| 
      
 512 
     | 
    
         
            +
              end
         
     | 
| 
      
 513 
     | 
    
         
            +
            end
         
     | 
| 
      
 514 
     | 
    
         
            +
            ```
         
     | 
| 
      
 515 
     | 
    
         
            +
             
     | 
| 
      
 516 
     | 
    
         
            +
            #### **Inheritance and Modifications**
         
     | 
| 
      
 517 
     | 
    
         
            +
             
     | 
| 
      
 518 
     | 
    
         
            +
            Element modifications work seamlessly with class inheritance:
         
     | 
| 
      
 519 
     | 
    
         
            +
             
     | 
| 
      
 520 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 521 
     | 
    
         
            +
            class BaseForm < ActionForm::Base
         
     | 
| 
      
 522 
     | 
    
         
            +
              element :name do
         
     | 
| 
      
 523 
     | 
    
         
            +
                input type: :text
         
     | 
| 
      
 524 
     | 
    
         
            +
                output type: :string
         
     | 
| 
      
 525 
     | 
    
         
            +
              end
         
     | 
| 
      
 526 
     | 
    
         
            +
            end
         
     | 
| 
      
 527 
     | 
    
         
            +
             
     | 
| 
      
 528 
     | 
    
         
            +
            class UserForm < BaseForm
         
     | 
| 
      
 529 
     | 
    
         
            +
              element :email do
         
     | 
| 
      
 530 
     | 
    
         
            +
                input type: :email
         
     | 
| 
      
 531 
     | 
    
         
            +
                output type: :string
         
     | 
| 
      
 532 
     | 
    
         
            +
              end
         
     | 
| 
      
 533 
     | 
    
         
            +
            end
         
     | 
| 
      
 534 
     | 
    
         
            +
             
     | 
| 
      
 535 
     | 
    
         
            +
            # Modify inherited elements
         
     | 
| 
      
 536 
     | 
    
         
            +
            UserForm.name_element do
         
     | 
| 
      
 537 
     | 
    
         
            +
              output type: :string, presence: true
         
     | 
| 
      
 538 
     | 
    
         
            +
            end
         
     | 
| 
      
 539 
     | 
    
         
            +
             
     | 
| 
      
 540 
     | 
    
         
            +
            # Modify elements defined in subclass
         
     | 
| 
      
 541 
     | 
    
         
            +
            UserForm.email_element do
         
     | 
| 
      
 542 
     | 
    
         
            +
              output type: :string, presence: true
         
     | 
| 
      
 543 
     | 
    
         
            +
            end
         
     | 
| 
      
 544 
     | 
    
         
            +
            ```
         
     | 
| 
      
 545 
     | 
    
         
            +
             
     | 
| 
      
 546 
     | 
    
         
            +
            Here's a complete example showing element modifications in action:
         
     | 
| 
      
 547 
     | 
    
         
            +
             
     | 
| 
      
 548 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 549 
     | 
    
         
            +
            class OrderForm < ActionForm::Base
         
     | 
| 
      
 550 
     | 
    
         
            +
              element :name do
         
     | 
| 
      
 551 
     | 
    
         
            +
                input(type: :text)
         
     | 
| 
      
 552 
     | 
    
         
            +
                output(type: :string)
         
     | 
| 
      
 553 
     | 
    
         
            +
              end
         
     | 
| 
      
 554 
     | 
    
         
            +
             
     | 
| 
      
 555 
     | 
    
         
            +
              subform :customer do
         
     | 
| 
      
 556 
     | 
    
         
            +
                element :name do
         
     | 
| 
      
 557 
     | 
    
         
            +
                  input(type: :text)
         
     | 
| 
      
 558 
     | 
    
         
            +
                  output(type: :string)
         
     | 
| 
      
 559 
     | 
    
         
            +
                end
         
     | 
| 
      
 560 
     | 
    
         
            +
              end
         
     | 
| 
      
 561 
     | 
    
         
            +
             
     | 
| 
      
 562 
     | 
    
         
            +
              many :items do
         
     | 
| 
      
 563 
     | 
    
         
            +
                subform do
         
     | 
| 
      
 564 
     | 
    
         
            +
                  element :name do
         
     | 
| 
      
 565 
     | 
    
         
            +
                    input(type: :text)
         
     | 
| 
      
 566 
     | 
    
         
            +
                    output(type: :string)
         
     | 
| 
      
 567 
     | 
    
         
            +
                  end
         
     | 
| 
      
 568 
     | 
    
         
            +
             
     | 
| 
      
 569 
     | 
    
         
            +
                  element :quantity do
         
     | 
| 
      
 570 
     | 
    
         
            +
                    input(type: :number)
         
     | 
| 
      
 571 
     | 
    
         
            +
                    output(type: :integer)
         
     | 
| 
      
 572 
     | 
    
         
            +
                  end
         
     | 
| 
      
 573 
     | 
    
         
            +
             
     | 
| 
      
 574 
     | 
    
         
            +
                  element :price do
         
     | 
| 
      
 575 
     | 
    
         
            +
                    input(type: :number)
         
     | 
| 
      
 576 
     | 
    
         
            +
                    output(type: :float)
         
     | 
| 
      
 577 
     | 
    
         
            +
                  end
         
     | 
| 
      
 578 
     | 
    
         
            +
                end
         
     | 
| 
      
 579 
     | 
    
         
            +
              end
         
     | 
| 
      
 580 
     | 
    
         
            +
            end
         
     | 
| 
      
 581 
     | 
    
         
            +
             
     | 
| 
      
 582 
     | 
    
         
            +
            # Apply modifications to add validation
         
     | 
| 
      
 583 
     | 
    
         
            +
            secure = true
         
     | 
| 
      
 584 
     | 
    
         
            +
             
     | 
| 
      
 585 
     | 
    
         
            +
            OrderForm.name_element do
         
     | 
| 
      
 586 
     | 
    
         
            +
              output(type: :string, presence: true, if: -> { secure })
         
     | 
| 
      
 587 
     | 
    
         
            +
            end
         
     | 
| 
      
 588 
     | 
    
         
            +
             
     | 
| 
      
 589 
     | 
    
         
            +
            OrderForm.customer_subform default: {} do
         
     | 
| 
      
 590 
     | 
    
         
            +
              name_element do
         
     | 
| 
      
 591 
     | 
    
         
            +
                output(type: :string, presence: true, if: -> { secure })
         
     | 
| 
      
 592 
     | 
    
         
            +
              end
         
     | 
| 
      
 593 
     | 
    
         
            +
            end
         
     | 
| 
      
 594 
     | 
    
         
            +
             
     | 
| 
      
 595 
     | 
    
         
            +
            OrderForm.items_subforms default: [{}] do
         
     | 
| 
      
 596 
     | 
    
         
            +
              subform do
         
     | 
| 
      
 597 
     | 
    
         
            +
                name_element do
         
     | 
| 
      
 598 
     | 
    
         
            +
                  output(type: :string, presence: true, if: -> { secure })
         
     | 
| 
      
 599 
     | 
    
         
            +
                end
         
     | 
| 
      
 600 
     | 
    
         
            +
                quantity_element do
         
     | 
| 
      
 601 
     | 
    
         
            +
                  output(type: :integer, presence: true, if: -> { secure })
         
     | 
| 
      
 602 
     | 
    
         
            +
                end
         
     | 
| 
      
 603 
     | 
    
         
            +
                price_element do
         
     | 
| 
      
 604 
     | 
    
         
            +
                  output(type: :float, presence: true, if: -> { secure })
         
     | 
| 
      
 605 
     | 
    
         
            +
                end
         
     | 
| 
      
 606 
     | 
    
         
            +
              end
         
     | 
| 
      
 607 
     | 
    
         
            +
            end
         
     | 
| 
      
 608 
     | 
    
         
            +
             
     | 
| 
      
 609 
     | 
    
         
            +
            # Now the form has validation enabled
         
     | 
| 
      
 610 
     | 
    
         
            +
            params = OrderForm.params_definition.new({})
         
     | 
| 
      
 611 
     | 
    
         
            +
            expect(params).to be_invalid
         
     | 
| 
      
 612 
     | 
    
         
            +
            ```
         
     | 
| 
      
 613 
     | 
    
         
            +
             
     | 
| 
      
 614 
     | 
    
         
            +
            #### **Key Benefits**
         
     | 
| 
      
 615 
     | 
    
         
            +
             
     | 
| 
      
 616 
     | 
    
         
            +
            - **Non-Destructive**: Modify form definitions without changing the original class
         
     | 
| 
      
 617 
     | 
    
         
            +
            - **Conditional Logic**: Apply modifications based on runtime conditions
         
     | 
| 
      
 618 
     | 
    
         
            +
            - **Inheritance Support**: Works seamlessly with class inheritance
         
     | 
| 
      
 619 
     | 
    
         
            +
            - **Flexible Extension**: Add validation, change defaults, or add new elements to existing definitions
         
     | 
| 
      
 620 
     | 
    
         
            +
            - **Reusability**: Create base forms and customize them for specific use cases
         
     | 
| 
      
 621 
     | 
    
         
            +
             
     | 
| 
      
 622 
     | 
    
         
            +
            This feature provides a powerful way to customize and extend form definitions while maintaining the declarative nature of ActionForm.
         
     | 
| 
      
 623 
     | 
    
         
            +
             
     | 
| 
       253 
624 
     | 
    
         
             
            ### Tagging system
         
     | 
| 
       254 
625 
     | 
    
         | 
| 
       255 
626 
     | 
    
         
             
            ActionForm includes a flexible tagging system that allows you to add custom metadata to form elements and control rendering behavior. Tags serve multiple purposes:
         
     | 
| 
         @@ -800,6 +1171,22 @@ class UserForm < ActionForm::Rails::Base 
     | 
|
| 
       800 
1171 
     | 
    
         
             
                input type: :email
         
     | 
| 
       801 
1172 
     | 
    
         
             
                output type: :string, presence: true
         
     | 
| 
       802 
1173 
     | 
    
         
             
              end
         
     | 
| 
      
 1174 
     | 
    
         
            +
             
     | 
| 
      
 1175 
     | 
    
         
            +
              element :password do
         
     | 
| 
      
 1176 
     | 
    
         
            +
                input type: :password
         
     | 
| 
      
 1177 
     | 
    
         
            +
                output type: :string
         
     | 
| 
      
 1178 
     | 
    
         
            +
              end
         
     | 
| 
      
 1179 
     | 
    
         
            +
             
     | 
| 
      
 1180 
     | 
    
         
            +
              element :password_confirmation do
         
     | 
| 
      
 1181 
     | 
    
         
            +
                input type: :password
         
     | 
| 
      
 1182 
     | 
    
         
            +
                output type: :string
         
     | 
| 
      
 1183 
     | 
    
         
            +
              end
         
     | 
| 
      
 1184 
     | 
    
         
            +
             
     | 
| 
      
 1185 
     | 
    
         
            +
              # Custom parameter validation for Rails integration
         
     | 
| 
      
 1186 
     | 
    
         
            +
              params do
         
     | 
| 
      
 1187 
     | 
    
         
            +
                validates :password, presence: true, length: { minimum: 6 }
         
     | 
| 
      
 1188 
     | 
    
         
            +
                validates :password, confirmation: true
         
     | 
| 
      
 1189 
     | 
    
         
            +
              end
         
     | 
| 
       803 
1190 
     | 
    
         
             
            end
         
     | 
| 
       804 
1191 
     | 
    
         
             
            ```
         
     | 
| 
       805 
1192 
     | 
    
         | 
| 
         @@ -910,6 +1297,7 @@ class UsersController < ApplicationController 
     | 
|
| 
       910 
1297 
     | 
    
         
             
                  @user = User.create!(user_params.user.to_h)
         
     | 
| 
       911 
1298 
     | 
    
         
             
                  redirect_to @user
         
     | 
| 
       912 
1299 
     | 
    
         
             
                else
         
     | 
| 
      
 1300 
     | 
    
         
            +
                  # Custom validation errors are automatically available
         
     | 
| 
       913 
1301 
     | 
    
         
             
                  @form = @form.with_params(user_params)
         
     | 
| 
       914 
1302 
     | 
    
         
             
                  render :new
         
     | 
| 
       915 
1303 
     | 
    
         
             
                end
         
     | 
| 
         @@ -927,6 +1315,7 @@ class UsersController < ApplicationController 
     | 
|
| 
       927 
1315 
     | 
    
         
             
                  @user.update!(user_params.user.to_h)
         
     | 
| 
       928 
1316 
     | 
    
         
             
                  redirect_to @user
         
     | 
| 
       929 
1317 
     | 
    
         
             
                else
         
     | 
| 
      
 1318 
     | 
    
         
            +
                  # Custom validation errors (like password confirmation) are displayed
         
     | 
| 
       930 
1319 
     | 
    
         
             
                  @form = @form.with_params(user_params)
         
     | 
| 
       931 
1320 
     | 
    
         
             
                  render :edit
         
     | 
| 
       932 
1321 
     | 
    
         
             
                end
         
     | 
| 
         @@ -26,6 +26,9 @@ module ActionForm 
     | 
|
| 
       26 
26 
     | 
    
         
             
                  def element(name, &block)
         
     | 
| 
       27 
27 
     | 
    
         
             
                    elements[name] = Class.new(ActionForm::Element)
         
     | 
| 
       28 
28 
     | 
    
         
             
                    elements[name].class_eval(&block)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    define_singleton_method(:"#{name}_element") do |klass = nil, &block|
         
     | 
| 
      
 30 
     | 
    
         
            +
                      update_element_definition(name, klass, &block)
         
     | 
| 
      
 31 
     | 
    
         
            +
                    end
         
     | 
| 
       29 
32 
     | 
    
         
             
                  end
         
     | 
| 
       30 
33 
     | 
    
         | 
| 
       31 
34 
     | 
    
         
             
                  def many(name, default: nil, &block)
         
     | 
| 
         @@ -34,12 +37,26 @@ module ActionForm 
     | 
|
| 
       34 
37 
     | 
    
         
             
                    subform_definition.class_eval(&block) if block
         
     | 
| 
       35 
38 
     | 
    
         
             
                    elements[name] = subform_definition
         
     | 
| 
       36 
39 
     | 
    
         
             
                    elements[name].default = default if default
         
     | 
| 
      
 40 
     | 
    
         
            +
                    define_singleton_method(:"#{name}_subforms") do |klass = nil, default: nil, &block|
         
     | 
| 
      
 41 
     | 
    
         
            +
                      update_element_definition(name, klass, default: default, &block)
         
     | 
| 
      
 42 
     | 
    
         
            +
                    end
         
     | 
| 
       37 
43 
     | 
    
         
             
                  end
         
     | 
| 
       38 
44 
     | 
    
         | 
| 
       39 
45 
     | 
    
         
             
                  def subform(name, default: nil, &block)
         
     | 
| 
       40 
46 
     | 
    
         
             
                    elements[name] = Class.new(subform_class)
         
     | 
| 
       41 
47 
     | 
    
         
             
                    elements[name].class_eval(&block)
         
     | 
| 
       42 
48 
     | 
    
         
             
                    elements[name].default = default if default
         
     | 
| 
      
 49 
     | 
    
         
            +
                    define_singleton_method(:"#{name}_subform") do |klass = nil, default: nil, &block|
         
     | 
| 
      
 50 
     | 
    
         
            +
                      update_element_definition(name, klass, default: default, &block)
         
     | 
| 
      
 51 
     | 
    
         
            +
                    end
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  private
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                  def update_element_definition(name, klass = nil, default: nil, &block)
         
     | 
| 
      
 57 
     | 
    
         
            +
                    elements[name] = klass if klass
         
     | 
| 
      
 58 
     | 
    
         
            +
                    elements[name] = Class.new(elements[name], &block) if block
         
     | 
| 
      
 59 
     | 
    
         
            +
                    elements[name].default = default if default
         
     | 
| 
       43 
60 
     | 
    
         
             
                  end
         
     | 
| 
       44 
61 
     | 
    
         
             
                end
         
     | 
| 
       45 
62 
     | 
    
         
             
              end
         
     | 
    
        data/lib/action_form/subform.rb
    CHANGED
    
    | 
         @@ -11,6 +11,13 @@ module ActionForm 
     | 
|
| 
       11 
11 
     | 
    
         | 
| 
       12 
12 
     | 
    
         
             
                class << self
         
     | 
| 
       13 
13 
     | 
    
         
             
                  attr_accessor :default
         
     | 
| 
      
 14 
     | 
    
         
            +
                  attr_writer :elements
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  def inherited(subclass)
         
     | 
| 
      
 17 
     | 
    
         
            +
                    super
         
     | 
| 
      
 18 
     | 
    
         
            +
                    subclass.elements = elements.dup
         
     | 
| 
      
 19 
     | 
    
         
            +
                    subclass.default = default.dup
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
       14 
21 
     | 
    
         
             
                end
         
     | 
| 
       15 
22 
     | 
    
         | 
| 
       16 
23 
     | 
    
         
             
                attr_reader :elements_instances, :tags, :name, :object
         
     | 
| 
         @@ -12,13 +12,19 @@ module ActionForm 
     | 
|
| 
       12 
12 
     | 
    
         
             
                attr_accessor :helpers
         
     | 
| 
       13 
13 
     | 
    
         | 
| 
       14 
14 
     | 
    
         
             
                class << self
         
     | 
| 
       15 
     | 
    
         
            -
                   
     | 
| 
       16 
     | 
    
         
            -
                  attr_accessor :default, :host_class
         
     | 
| 
      
 15 
     | 
    
         
            +
                  attr_accessor :default, :host_class, :subform_definition
         
     | 
| 
       17 
16 
     | 
    
         | 
| 
       18 
17 
     | 
    
         
             
                  def subform(subform_class = nil, &block)
         
     | 
| 
       19 
     | 
    
         
            -
                    @subform_definition  
     | 
| 
      
 18 
     | 
    
         
            +
                    @subform_definition ||= subform_class || Class.new(host_class.subform_class)
         
     | 
| 
       20 
19 
     | 
    
         
             
                    @subform_definition.class_eval(&block) if block
         
     | 
| 
       21 
20 
     | 
    
         
             
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  def inherited(subclass)
         
     | 
| 
      
 23 
     | 
    
         
            +
                    super
         
     | 
| 
      
 24 
     | 
    
         
            +
                    subclass.subform_definition = subform_definition
         
     | 
| 
      
 25 
     | 
    
         
            +
                    subclass.default = default
         
     | 
| 
      
 26 
     | 
    
         
            +
                    subclass.host_class = host_class
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
       22 
28 
     | 
    
         
             
                end
         
     | 
| 
       23 
29 
     | 
    
         | 
| 
       24 
30 
     | 
    
         
             
                def initialize(name)
         
     | 
    
        data/lib/action_form/version.rb
    CHANGED