permit_params 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6e0261ffbdf435bd7abca5dd4f6fba035c695568e8eb731f5bd0422697114431
4
+ data.tar.gz: 011cbef5ce2019c59e48a33e3d8e4f6e0fd03e8ae8b713ad63e088cb69d29cc2
5
+ SHA512:
6
+ metadata.gz: 8fceb998fc9889aff5fc65bc7245d043daac8d0d627b84c8e7a236e805f36bd0f766ab4aa7548dd96f015d368cd7da0c23a8c9c9b3a4e921b851da932f47461a
7
+ data.tar.gz: 6c2eacdaacb3746178ca59fea8b3121b47882fcced29e4218cea46f6e537ceac94a12887666f44dcda9188ce888189e6da32dd4a13a7dfc33d3b3e4a63a2e9eb
data/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+
5
+ - Versão inicial.
6
+ - Macro `permit_params` para declarar schemas de parâmetros por action.
7
+ - Suporte a `permit`, `required` + `permit` e `expect` (Rails 8).
8
+ - Atalho de array para `permit`.
9
+ - Configuração global (`default_schema`, `raise_on_missing_schema`) via
10
+ `PermitParams.configure`.
11
+ - Generator `permit_params:install`.
12
+ - Inclusão automática em `ActionController::Base`/`ActionController::API`
13
+ através de um Railtie.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Ronsal
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,183 @@
1
+ # permit_params
2
+
3
+ Schemas de parâmetros **declarativos e por action** para controllers Rails.
4
+
5
+ Declare o que cada action espera e a gem cuida do `strong parameters` automaticamente.
6
+ Suporta `permit`, `required` + `permit` e a API nova `expect` do Rails 8.
7
+
8
+ ```ruby
9
+ class HeroesController < ApplicationController
10
+ permit_params :show, { permit: [:id, { hero: {} }] }
11
+ permit_params :search, { permit: [:query, :page, :per_page, { filter: [] }, { sort: [] }] }
12
+ permit_params :create, { required: :hero, permit: [:name, :rank, :lat, :lng] }
13
+ permit_params :update, { expect: { hero: [:id, :name, :rank, :lat, :lng] } }
14
+
15
+ def show
16
+ status, content, serializer = Http::ShowHero::Service.(params)
17
+ render json: content, status: status, serializer: serializer
18
+ end
19
+ end
20
+ ```
21
+
22
+ ## Como funciona
23
+
24
+ - A gem é incluída automaticamente em `ActionController::Base` e
25
+ `ActionController::API` (via Railtie). **Instalar já basta.**
26
+ - `permit_params :action, schema` guarda o schema por action.
27
+ - No momento em que a action chama `params`, o schema da action é aplicado.
28
+ - Actions sem schema continuam recebendo o `params` padrão do framework
29
+ (a menos que você configure `default_schema`/`raise_on_missing_schema`).
30
+
31
+ ## Instalação
32
+
33
+ ### Publicada no Rubygems
34
+
35
+ ```ruby
36
+ # Gemfile
37
+ gem "permit_params"
38
+ ```
39
+
40
+ ### Como gem local (path)
41
+
42
+ ```ruby
43
+ # Gemfile
44
+ gem "permit_params", path: "../permit_params"
45
+ ```
46
+
47
+ Depois:
48
+
49
+ ```bash
50
+ bundle install
51
+ ```
52
+
53
+ Opcionalmente, gere o initializer de configuração:
54
+
55
+ ```bash
56
+ rails generate permit_params:install
57
+ ```
58
+
59
+ ## Formatos de schema
60
+
61
+ ### `permit`
62
+
63
+ Equivale a `params.permit(*...)`:
64
+
65
+ ```ruby
66
+ permit_params :show, { permit: [:id, { hero: {} }] }
67
+ # params.permit(:id, hero: {})
68
+ ```
69
+
70
+ > `hero: {}` permite **todas** as chaves de dentro de `hero`.
71
+ > Para filtrar o conteúdo, liste as chaves: `{ hero: [:name] }`.
72
+
73
+ ### `required` + `permit`
74
+
75
+ Equivale a `params.required(:chave).permit(*...)`. Como o `require` do Rails
76
+ **desembrulha** a chave, o resultado já são os atributos internos:
77
+
78
+ ```ruby
79
+ permit_params :create, { required: :hero, permit: [:name, :rank, :lat, :lng] }
80
+ # params.required(:hero).permit(:name, :rank, :lat, :lng)
81
+ # => params com name/rank/lat/lng no topo
82
+ ```
83
+
84
+ ### `expect` (Rails 8+)
85
+
86
+ Equivale a `params.expect(...)`. Quando o schema tem uma única chave raiz, o
87
+ Rails também desembrulha o conteúdo:
88
+
89
+ ```ruby
90
+ permit_params :update, { expect: { hero: [:id, :name, :rank, :lat, :lng] } }
91
+ # params.expect(hero: [:id, :name, :rank, :lat, :lng])
92
+ # => params com id/name/rank/lat/lng no topo
93
+ ```
94
+
95
+ Para **arrays** de hashes use os colchetes duplos (regra do próprio Rails):
96
+
97
+ ```ruby
98
+ permit_params :bulk, { expect: { heroes: [[:id, :name, :rank]] } }
99
+ ```
100
+
101
+ ### Atalho com array
102
+
103
+ Um array puro vira um `permit`:
104
+
105
+ ```ruby
106
+ permit_params :index, [:page, :per_page]
107
+ # o mesmo que permit: [:page, :per_page]
108
+ ```
109
+
110
+ ## Configuração global
111
+
112
+ ```ruby
113
+ # config/initializers/permit_params.rb
114
+ PermitParams.configure do |config|
115
+ # Schema aplicado a actions que não declaram o próprio schema.
116
+ # nil (padrão) mantém o params padrão do framework.
117
+ config.default_schema = { permit: [:page, :per_page] }
118
+
119
+ # Levanta PermitParams::MissingSchemaError para actions sem schema.
120
+ config.raise_on_missing_schema = false
121
+ end
122
+ ```
123
+
124
+ ## Erros
125
+
126
+ | Erro | Quando acontece |
127
+ | -------------------------------------- | ---------------------------------------------------------------------- |
128
+ | `PermitParams::InvalidSchemaError` | Schema não é Array nem Hash com `:permit`, `:required` ou `:expect`. |
129
+ | `PermitParams::MissingSchemaError` | Action sem schema com `raise_on_missing_schema` ligado. |
130
+ | `PermitParams::Error` | `expect:` usado em uma versão de Rails sem `Parameters#expect` (< 8.0).|
131
+ | `ActionController::ParameterMissing` | Chave obrigatória ausente (`required`/`expect`). |
132
+
133
+ ## Migrando do `BaseController`
134
+
135
+ Antes (implementação manual):
136
+
137
+ ```ruby
138
+ class BaseController < ApplicationController
139
+ class_attribute :param_schemas, default: {}
140
+
141
+ class << self
142
+ def permit_params(action, schema)
143
+ param_schemas[action.to_sym] = schema
144
+ end
145
+ end
146
+
147
+ private
148
+
149
+ def params
150
+ schema = self.class.param_schemas[action_name.to_sym]
151
+ return super unless schema
152
+ # ...
153
+ end
154
+ end
155
+ ```
156
+
157
+ Depois (com a gem instalada, o `BaseController` pode ficar vazio ou ser removido):
158
+
159
+ ```ruby
160
+ class BaseController < ApplicationController
161
+ end
162
+ ```
163
+
164
+ > Bônus: a implementação manual mutava o mesmo Hash compartilhado entre todos
165
+ > os controllers (schemas vazavam de um controller para o outro). A gem usa
166
+ > `merge`, então cada controller tem seu próprio conjunto de schemas.
167
+
168
+ ## Requisitos
169
+
170
+ - Ruby >= 3.1
171
+ - `actionpack`/`activesupport` >= 7.0
172
+ - `expect:` exige Rails >= 8.0
173
+
174
+ ## Desenvolvimento
175
+
176
+ ```bash
177
+ bundle install
178
+ bundle exec rspec
179
+ ```
180
+
181
+ ## Licença
182
+
183
+ MIT.
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module PermitParams
6
+ module Generators
7
+ # Creates +config/initializers/permit_params.rb+.
8
+ #
9
+ # rails generate permit_params:install
10
+ class InstallGenerator < ::Rails::Generators::Base
11
+ source_root File.expand_path("templates", __dir__)
12
+
13
+ desc "Creates a PermitParams initializer."
14
+
15
+ def copy_initializer
16
+ template "permit_params.rb", "config/initializers/permit_params.rb"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ PermitParams.configure do |config|
4
+ # Schema applied to actions that do not declare their own through
5
+ # `permit_params`. Leave it as nil (the default) to keep the framework
6
+ # default for those actions.
7
+ #
8
+ # config.default_schema = { permit: [:page, :per_page] }
9
+
10
+ # Raise PermitParams::MissingSchemaError when an action has neither its own
11
+ # schema nor a default_schema. Handy to force every action to be explicit.
12
+ #
13
+ # config.raise_on_missing_schema = false
14
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PermitParams
4
+ # Global configuration for the gem. Change it through +PermitParams.configure+,
5
+ # usually in +config/initializers/permit_params.rb+:
6
+ #
7
+ # PermitParams.configure do |config|
8
+ # config.default_schema = { permit: [:page, :per_page] }
9
+ # config.raise_on_missing_schema = true
10
+ # end
11
+ class Configuration
12
+ # Schema applied to actions that do not declare their own through
13
+ # +permit_params+. Accepts the same shapes as +permit_params+ (a Hash like
14
+ # <tt>{ permit: [...] }</tt>, <tt>{ required: :foo, permit: [...] }</tt> or
15
+ # <tt>{ expect: { ... } }</tt>, or a bare Array as shorthand for +permit+).
16
+ #
17
+ # When +nil+ (the default) actions without a schema are left untouched and
18
+ # receive the framework default +params+.
19
+ attr_accessor :default_schema
20
+
21
+ # When +true+, raises PermitParams::MissingSchemaError for any action that
22
+ # has neither its own schema nor a +default_schema+. Useful to enforce that
23
+ # every action is explicit. Defaults to +false+.
24
+ attr_accessor :raise_on_missing_schema
25
+
26
+ def initialize
27
+ @default_schema = nil
28
+ @raise_on_missing_schema = false
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+ require "active_support/core_ext/class/attribute"
5
+
6
+ module PermitParams
7
+ # Mixin that adds the +permit_params+ class macro and applies the schema
8
+ # declared for the current action to +params+.
9
+ #
10
+ # It is included automatically into +ActionController::Base+ and
11
+ # +ActionController::API+ by PermitParams::Railtie, so in a Rails app you
12
+ # usually do not need to include it yourself.
13
+ module Controller
14
+ extend ActiveSupport::Concern
15
+
16
+ included do
17
+ class_attribute :param_schemas, instance_accessor: false, default: {}
18
+ end
19
+
20
+ class_methods do
21
+ # Declares the parameter schema for +action+.
22
+ #
23
+ # permit_params :show, { permit: [:id, { hero: {} }] }
24
+ # permit_params :create, required: :hero, permit: [:name, :rank]
25
+ # permit_params :update, expect: { hero: [:id, :name, :rank] }
26
+ # permit_params :index, [:page, :per_page] # shorthand for permit
27
+ #
28
+ # The schema is validated eagerly, so a malformed one fails while the
29
+ # class is being (re)loaded instead of on the first request.
30
+ def permit_params(action, schema = nil, **options)
31
+ schema = options if schema.nil? && !options.empty?
32
+ raise ArgumentError, "missing schema for action #{action.inspect}" if schema.nil?
33
+
34
+ schema = PermitParams.normalize_schema(schema)
35
+ self.param_schemas = param_schemas.merge(action.to_sym => schema)
36
+ end
37
+
38
+ # Schema for +action+, falling back to the global default when the action
39
+ # does not declare one.
40
+ def param_schema_for(action)
41
+ param_schemas[action.to_sym] || PermitParams.configuration.default_schema
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def params
48
+ schema = self.class.param_schema_for(action_name)
49
+
50
+ if schema.nil?
51
+ if PermitParams.configuration.raise_on_missing_schema
52
+ raise MissingSchemaError,
53
+ "no parameter schema declared for action #{action_name.inspect} on #{self.class}"
54
+ end
55
+
56
+ return super
57
+ end
58
+
59
+ PermitParams.apply(super, schema)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PermitParams
4
+ # Wires PermitParams::Controller into every controller as soon as
5
+ # ActionController is loaded, so installing the gem is enough to get the
6
+ # +permit_params+ DSL everywhere.
7
+ class Railtie < ::Rails::Railtie
8
+ initializer "permit_params.include_controller" do
9
+ # ActionController::Base and ActionController::API both run
10
+ # :action_controller in Rails 8. The other two hooks are kept so the gem
11
+ # also works on older versions; including the same module twice is a no-op.
12
+ ActiveSupport.on_load(:action_controller) do
13
+ include PermitParams::Controller
14
+ end
15
+
16
+ ActiveSupport.on_load(:action_controller_base) do
17
+ include PermitParams::Controller
18
+ end
19
+
20
+ ActiveSupport.on_load(:action_controller_api) do
21
+ include PermitParams::Controller
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PermitParams
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support"
4
+ require "active_support/core_ext/class/attribute"
5
+ require "active_support/concern"
6
+
7
+ require "permit_params/version"
8
+ require "permit_params/configuration"
9
+ require "permit_params/controller"
10
+ require "permit_params/railtie" if defined?(::Rails::Railtie)
11
+
12
+ # Declarative, per-action strong parameter schemas for Rails controllers.
13
+ #
14
+ # class HeroesController < ApplicationController
15
+ # permit_params :show, { permit: [:id, { hero: {} }] }
16
+ # permit_params :create, required: :hero, permit: [:name, :rank, :lat, :lng]
17
+ # permit_params :update, expect: { hero: [:id, :name, :rank, :lat, :lng] }
18
+ # end
19
+ module PermitParams
20
+ class Error < StandardError; end
21
+
22
+ # Raised when a schema is neither an Array nor a Hash with one of
23
+ # +:permit+, +:required+ or +:expect+.
24
+ class InvalidSchemaError < Error; end
25
+
26
+ # Raised for actions without a schema when
27
+ # +PermitParams.configuration.raise_on_missing_schema+ is enabled.
28
+ class MissingSchemaError < Error; end
29
+
30
+ class << self
31
+ # Current global configuration.
32
+ def configuration
33
+ @configuration ||= Configuration.new
34
+ end
35
+
36
+ # Yields the configuration for modification and returns it.
37
+ #
38
+ # PermitParams.configure do |config|
39
+ # config.default_schema = { permit: [:page, :per_page] }
40
+ # end
41
+ def configure
42
+ yield configuration if block_given?
43
+ configuration
44
+ end
45
+
46
+ # Restores the default configuration. Mainly useful in tests.
47
+ def reset_configuration!
48
+ @configuration = nil
49
+ end
50
+
51
+ # Applies +schema+ to an ActionController::Parameters instance and returns
52
+ # the filtered parameters.
53
+ def apply(params, schema)
54
+ schema = normalize_schema(schema)
55
+
56
+ if schema.key?(:expect)
57
+ expect_params(params, schema[:expect])
58
+ elsif schema.key?(:required)
59
+ params.required(schema[:required]).permit(*Array(schema[:permit]))
60
+ else
61
+ params.permit(*Array(schema[:permit]))
62
+ end
63
+ end
64
+
65
+ # Validates a schema and normalizes the Array shorthand into a Hash.
66
+ def normalize_schema(schema)
67
+ return { permit: schema } if schema.is_a?(Array)
68
+
69
+ unless schema.is_a?(Hash) && (schema.key?(:permit) || schema.key?(:required) || schema.key?(:expect))
70
+ raise InvalidSchemaError,
71
+ "schema must be an Array or a Hash with one of :permit, :required or :expect (got #{schema.inspect})"
72
+ end
73
+
74
+ schema
75
+ end
76
+
77
+ private
78
+
79
+ def expect_params(params, filters)
80
+ unless params.respond_to?(:expect)
81
+ raise Error, "`expect:` schemas require ActionController::Parameters#expect (Rails >= 8.0)"
82
+ end
83
+
84
+ params.expect(filters)
85
+ end
86
+ end
87
+ end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: permit_params
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Lasnor
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: actionpack
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '7.0'
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '9.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: '7.0'
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '9.0'
32
+ - !ruby/object:Gem::Dependency
33
+ name: activesupport
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '7.0'
39
+ - - "<"
40
+ - !ruby/object:Gem::Version
41
+ version: '9.0'
42
+ type: :runtime
43
+ prerelease: false
44
+ version_requirements: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '7.0'
49
+ - - "<"
50
+ - !ruby/object:Gem::Version
51
+ version: '9.0'
52
+ description: |
53
+ permit_params adds a `permit_params` class macro that lets you declare the
54
+ expected parameters for each controller action and applies them automatically.
55
+ It supports `permit`, `required` + `permit`, and the Rails 8 `expect` API, and
56
+ is included into every ActionController::Base/ActionController::API by a Railtie.
57
+ email:
58
+ - leandrolsnr@gmail.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - CHANGELOG.md
64
+ - LICENSE.txt
65
+ - README.md
66
+ - lib/generators/permit_params/install/install_generator.rb
67
+ - lib/generators/permit_params/install/templates/permit_params.rb
68
+ - lib/permit_params.rb
69
+ - lib/permit_params/configuration.rb
70
+ - lib/permit_params/controller.rb
71
+ - lib/permit_params/railtie.rb
72
+ - lib/permit_params/version.rb
73
+ homepage: https://github.com/leandrolasnor/permit_params
74
+ licenses:
75
+ - MIT
76
+ metadata:
77
+ homepage_uri: https://github.com/leandrolasnor/permit_params
78
+ source_code_uri: https://github.com/leandrolasnor/permit_params
79
+ changelog_uri: https://github.com/leandrolasnor/permit_params/blob/main/CHANGELOG.md
80
+ rubygems_mfa_required: 'true'
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '3.1'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubygems_version: 4.0.20
96
+ specification_version: 4
97
+ summary: Declarative, per-action strong parameter schemas for Rails controllers.
98
+ test_files: []