auto_strong_parameters 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +103 -0
- data/Rakefile +11 -0
- data/lib/auto_strong_parameters/auto_form_params.rb +71 -0
- data/lib/auto_strong_parameters/auto_permit.rb +19 -0
- data/lib/auto_strong_parameters/controller_permitter.rb +2 -0
- data/lib/auto_strong_parameters/railtie.rb +28 -0
- data/lib/auto_strong_parameters/version.rb +3 -0
- data/lib/auto_strong_parameters.rb +79 -0
- data/test/apps/basic_controller.rb +47 -0
- data/test/apps/models.rb +3 -0
- data/test/apps/parent.rb +5 -0
- data/test/apps/pet.rb +5 -0
- data/test/apps/rails42.rb +57 -0
- data/test/apps/rails52.rb +57 -0
- data/test/apps/rails60.rb +57 -0
- data/test/apps/rails61.rb +57 -0
- data/test/apps/rails70.rb +56 -0
- data/test/apps/routes.rb +7 -0
- data/test/apps/test_app.rb +13 -0
- data/test/apps/user.rb +23 -0
- data/test/auto_form_params_test.rb +54 -0
- data/test/auto_permit_test.rb +71 -0
- data/test/auto_strong_parameters_test.rb +16 -0
- data/test/test_helper.rb +23 -0
- metadata +152 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7957f41175cec758139ef39f6b1b1889b7d164c51b658cf09ad58f9a14fc8b9e
|
4
|
+
data.tar.gz: a5775efa5e7ad60032c7915832bc86f5119bf3496e9a16269a922c6ab696ee08
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 68b0628b21442f52584f689266f736e62ce810ecfb629d94208e8ea72d531c210243e0952ffcaca46bbfbe579a0cfb5ae37aebbf83910e3817ed7183e593760d
|
7
|
+
data.tar.gz: 71a53c2f1d3ee226d73ea6f8f8467f76e10b35b2cd02e6cd18b5241f53c13077f038abacc2286ee5fba06d65361b6cd33c3cd6110f720885699a096498c71c20
|
data/README.md
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
# Auto Strong Parameters
|
2
|
+
|
3
|
+
Auto Strong Parameters detects the fields included in a form and automatically permits them in the controller. You no longer need to manually enumerate the params you've submitted. You can fall back to standard Strong Parameters when you need custom behavior.
|
4
|
+
|
5
|
+
Rails 4.0 introduced Rails developers to the world of Strong Parameters. This gem is an extension to the model that Strong Parameters introduced, intended to reduce or eliminate the busy work that Strong Paramters introduced. As Giles Bowkett wrote, "tedious, repetitive work is for computers to do."
|
6
|
+
|
7
|
+
- :white_check_mark: Seamless integration: replace `require(key).permit` calls with `auto_permit!(key)`
|
8
|
+
- :safety_vest: Safe from malicious tampering due to message signing
|
9
|
+
- :trophy: Graceful upgrade and fallback to standard Strong Parameters
|
10
|
+
- :bow: No more busy work enumerating permitted parameters twice
|
11
|
+
|
12
|
+
## How it works (TL;DR)
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
# Replace this...
|
16
|
+
user_params = params.require(:user).permit(:first_name, :email)
|
17
|
+
|
18
|
+
# ...with this
|
19
|
+
user_params = params.auto_permit!(:user)
|
20
|
+
```
|
21
|
+
|
22
|
+
## How it works
|
23
|
+
|
24
|
+
Before:
|
25
|
+
```ruby
|
26
|
+
|
27
|
+
# View
|
28
|
+
<%= form_with @user do |f| %>
|
29
|
+
First name: <%= f.text_field :first_name %>
|
30
|
+
Email: <%= f.email_field :email %>
|
31
|
+
<% end %>
|
32
|
+
|
33
|
+
|
34
|
+
# Controller
|
35
|
+
user_params = params.require(:user).permit(:first_name, :email)
|
36
|
+
# => { first_name: "Dave", email: "dave@example.com }
|
37
|
+
@user = User.create(user_params)
|
38
|
+
```
|
39
|
+
|
40
|
+
After:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
# View - unchanged
|
44
|
+
<%= form_with @user do |f| %>
|
45
|
+
First name: <%= f.text_field :first_name %>
|
46
|
+
Email: <%= f.email_field :email %>
|
47
|
+
<% end %>
|
48
|
+
|
49
|
+
|
50
|
+
# Controller - no enumeration required, your form dictates what is allowed
|
51
|
+
user_params = params.auto_permit!(:user)
|
52
|
+
# => { first_name: "Dave", email: "dave@example.com }
|
53
|
+
@user = User.create(user_params)
|
54
|
+
```
|
55
|
+
|
56
|
+
|
57
|
+
## How to use
|
58
|
+
|
59
|
+
Add to your Gemfile, `bundle install` and go.
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
gem 'auto_strong_parameters'
|
63
|
+
```
|
64
|
+
|
65
|
+
## Motivation
|
66
|
+
|
67
|
+
The Rails 2.x design of including permitted attributes in the model was a limited design. Models could be updated by users of different roles and having a single list was too restrictive.
|
68
|
+
|
69
|
+
Strong Parameters moved permitted attribute assertions from the model to the controller. To this day, parameters are authorized in the controllers they are submitted to. This change was for the better because it meant that each controller could assert its own set of parameters.
|
70
|
+
|
71
|
+
Strong Parameters still has the problem that multiple forms can submit to a single controller action. This issues means developers must implement controller-side configuration and know where each submission is coming from so that the correct parameters are authorized for all allowed situations. Additionally, there is fundamentally always double entry of what parameters you want to save - once by adding an input to your form and once again in the controller.
|
72
|
+
|
73
|
+
This design suggests that we can go one step further. Parameters are literally setup when you write your form code in your view. Each `f.text_field` or `f.number_field` says that you want that parameter in the form and accepted by the server. The form itself is the documentation as to what parameters can be submitted.
|
74
|
+
|
75
|
+
The natural solution is for the framework to handle authorizing the parameters that the developer already told it to put in the form.
|
76
|
+
|
77
|
+
## Compatibility
|
78
|
+
|
79
|
+
Official support is currently set for all supported Rails releases as well as stable releases maintained by Rails LTS. There is no separate branch for separate versions, it is a goal keep this gem compatible for the life of Strong Parameters (Rails 4.0 - present).
|
80
|
+
|
81
|
+
- Ruby 2.7+, but should work fine with Ruby 2.0+
|
82
|
+
- Rails 4.2, 5.2, 6.0+
|
83
|
+
|
84
|
+
### Form Builders
|
85
|
+
|
86
|
+
Auto Strong Parameters currently only supports the built-in Rails form builder class. If you use a different form builder and would like to see it supported, open a ticket, or better yet, write it and contribute back!
|
87
|
+
|
88
|
+
### Unofficial compatibility
|
89
|
+
|
90
|
+
Our gemspec dictates Rails 4.0+ support but we do not test versions 4.0, 4.1, 5.0, or 5.1. It may work on those versions but it is not officially supported. This is a "use at your own risk" allowance - you should seriously reconsider running Rails 4.0/4.1 and 5.0/5.1 because they do not receive security updates or attention from official sources or private companies at all.
|
91
|
+
|
92
|
+
### Why support Rails 4+?
|
93
|
+
|
94
|
+
There are thousands of Rails apps on old versions of Rails maintained by small teams that are unable to perform version upgrades. This gem aims to help make working with Strong Parameters easier and more seamless - one less headache when considering whether and when to upgrade. This is one way we can help relieve the upgrade and maintenance burden for folks on old versions of Rails.
|
95
|
+
|
96
|
+
Long-term support for non-officially-supported versions of Rails is offered by [Rails LTS](https://railslts.com) (no official affiliation, just a happy customer). Since Rails LTS is the only way that you can get these old versions of Rails to work with current Ruby versions, this gem is tested against them rather than the final releases from [rails/rails](https://github.com/rails/rails). In order to successfully run all our tests, you may need a license to get a copy of Rails LTS 4.2.
|
97
|
+
|
98
|
+
All that said, AutoStrongParameters should work fine with standard Rails 4.2 even if you are running an EOL version of Ruby.
|
99
|
+
|
100
|
+
|
101
|
+
## Contributing
|
102
|
+
|
103
|
+
Contributions are welcome! If you use it and it doesn't work for you, please open an issue! If it DOES work for you, also let me know!
|
data/Rakefile
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AutoStrongParameters::AutoFormParams
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
attr_reader :_asp_fields
|
8
|
+
end
|
9
|
+
|
10
|
+
ASP_NAME_REGEX = /\sname=\"(.+?)\"/
|
11
|
+
ASP_DIGIT_REGEX = /\[\d+\]/
|
12
|
+
|
13
|
+
TRACKED_FIELDS = %w(
|
14
|
+
search_field telephone_field date_field time_field datetime_field
|
15
|
+
month_field week_field url_field email_field number_field range_field
|
16
|
+
file_field password_field text_area text_field radio_button
|
17
|
+
)
|
18
|
+
|
19
|
+
TRACKED_FIELDS.each do |name|
|
20
|
+
module_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
|
21
|
+
def #{name}(*args)
|
22
|
+
super.tap do |res|
|
23
|
+
_asp_track_field(res)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
RUBY_EVAL
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def _asp_track_field(field)
|
32
|
+
@_asp_fields ||= []
|
33
|
+
@_asp_fields << field.match(ASP_NAME_REGEX)[1].gsub(ASP_DIGIT_REGEX, '[]')
|
34
|
+
end
|
35
|
+
|
36
|
+
# Generate a hidden input with the signed value of the params shape for this
|
37
|
+
# form. Append to the form.
|
38
|
+
def _asp_hidden_tag
|
39
|
+
if _asp_fields.present?
|
40
|
+
# puts "========= Adding tag =========="
|
41
|
+
# puts _asp_fields.inspect
|
42
|
+
name = AutoStrongParameters.asp_message_key
|
43
|
+
to_sign = asp_fields_to_shape
|
44
|
+
signature = AutoStrongParameters.verifier.generate(to_sign)
|
45
|
+
|
46
|
+
"<input type='hidden' name='#{name}' value='#{signature}' />".html_safe
|
47
|
+
else
|
48
|
+
""
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# This implementation is taken from Rails 7.0 but is largely the same as the
|
53
|
+
# version found in Rails 4.2. Since Rails doesn't give us a nice hook to add
|
54
|
+
# in our functionality, we do it by bringing in the full method and
|
55
|
+
# augmenting it here.
|
56
|
+
def form_tag_with_body(html_options, content)
|
57
|
+
output = form_tag_html(html_options)
|
58
|
+
output << content.to_s if content
|
59
|
+
output << _asp_hidden_tag
|
60
|
+
output.safe_concat("</form>")
|
61
|
+
end
|
62
|
+
|
63
|
+
# Concatenate all form element "name" values into a valid query string, parse
|
64
|
+
# it with Rack, and then convert to a Strong Parameters "shape" to be signed
|
65
|
+
# and sent to the server.
|
66
|
+
def asp_fields_to_shape
|
67
|
+
AutoStrongParameters.to_strong_params_shape(
|
68
|
+
Rack::Utils.parse_nested_query(_asp_fields.join("=&") + "=")
|
69
|
+
)
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AutoStrongParameters
|
4
|
+
module AutoPermit
|
5
|
+
def auto_permit!(key)
|
6
|
+
shape = asp_auto_permitted_params(key)
|
7
|
+
|
8
|
+
require(key).permit(shape[key])
|
9
|
+
end
|
10
|
+
|
11
|
+
def asp_auto_permitted_params(key)
|
12
|
+
if sig = self[key][AutoStrongParameters.asp_message_key]
|
13
|
+
AutoStrongParameters.verifier.verify(sig) rescue {}
|
14
|
+
else
|
15
|
+
{}
|
16
|
+
end.with_indifferent_access
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'auto_strong_parameters/auto_permit'
|
2
|
+
require 'auto_strong_parameters/auto_form_params'
|
3
|
+
|
4
|
+
module AutoStrongParameters
|
5
|
+
require 'rails/railtie'
|
6
|
+
|
7
|
+
class Railtie < ::Rails::Railtie
|
8
|
+
initializer 'auto_strong_parameters.add_to_rails' do
|
9
|
+
ActiveSupport.on_load :action_view do
|
10
|
+
AutoStrongParameters::Railtie.apply_form_helpers_patch
|
11
|
+
end
|
12
|
+
|
13
|
+
ActiveSupport.on_load :action_controller do
|
14
|
+
AutoStrongParameters::Railtie.apply_auto_permit_patch
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Railtie
|
20
|
+
def self.apply_form_helpers_patch
|
21
|
+
ActionView::Base.send(:include, AutoStrongParameters::AutoFormParams)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.apply_auto_permit_patch
|
25
|
+
ActionController::Parameters.send(:include, AutoStrongParameters::AutoPermit)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails'
|
4
|
+
require 'auto_strong_parameters/railtie'
|
5
|
+
|
6
|
+
module AutoStrongParameters
|
7
|
+
# Rails' message_verifier exists with a stable API in all versions of Rails
|
8
|
+
# since 4.2.
|
9
|
+
def self.verifier
|
10
|
+
@verifier ||=
|
11
|
+
ActiveSupport::MessageVerifier.new("auto_strong_parameters", serializer: JSON)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Provide your own custom verifier for AutoStrongParameters. Must respond to
|
15
|
+
# #generate which takes an object and returns a string and #verify which
|
16
|
+
# takes a string and returns an object.
|
17
|
+
def self.verifier=(custom_verifier)
|
18
|
+
@verifier = custom_verifier
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.asp_message_key
|
22
|
+
@asp_message_key ||= :"_asp_params"
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.asp_message_key=(val)
|
26
|
+
@asp_message_key = val
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.to_strong_params_shape(obj)
|
30
|
+
items = Set.new
|
31
|
+
hsh = {}
|
32
|
+
|
33
|
+
case obj
|
34
|
+
when Hash
|
35
|
+
obj.each do |key, val|
|
36
|
+
case val
|
37
|
+
when Hash
|
38
|
+
hsh[key] ||= {}
|
39
|
+
hsh[key] = to_strong_params_shape(val)
|
40
|
+
when Array
|
41
|
+
hsh[key] ||= []
|
42
|
+
hsh[key] << to_strong_params_shape(val)
|
43
|
+
else
|
44
|
+
items << key.to_s
|
45
|
+
end
|
46
|
+
end
|
47
|
+
if hsh.empty?
|
48
|
+
items.flatten.to_a
|
49
|
+
elsif items.empty?
|
50
|
+
hsh
|
51
|
+
else
|
52
|
+
hsh.transform_values!(&:flatten)
|
53
|
+
[*items.flatten, hsh].flatten
|
54
|
+
end
|
55
|
+
|
56
|
+
when Array
|
57
|
+
obj.each do |item|
|
58
|
+
case item
|
59
|
+
when Hash
|
60
|
+
items << to_strong_params_shape(item)
|
61
|
+
when Array
|
62
|
+
items << to_strong_params_shape(item)
|
63
|
+
else
|
64
|
+
# nothing
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
if hsh.empty?
|
69
|
+
items.flatten.to_a
|
70
|
+
else
|
71
|
+
hsh.transform_values!(&:flatten)
|
72
|
+
[*items.flatten, hsh]
|
73
|
+
end
|
74
|
+
|
75
|
+
else
|
76
|
+
nil
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
class BasicController < ActionController::Base
|
2
|
+
include Rails.application.routes.url_helpers
|
3
|
+
|
4
|
+
self.view_paths = [ActionView::FixtureResolver.new(
|
5
|
+
"basic/new.html.erb" => <<~NEW_USER_FORM
|
6
|
+
<%= form_for @user, url: "/auto_permit" do |f| %>
|
7
|
+
<%= f.text_field :name %>
|
8
|
+
<%= email_field :user, :email %>
|
9
|
+
<%= f.text_area :description %>
|
10
|
+
<%= f.telephone_field :phone %>
|
11
|
+
<%= f.date_field :dob %>
|
12
|
+
<%= f.time_field :lunch_time %>
|
13
|
+
<%= f.datetime_field :confirmed_at %>
|
14
|
+
<%= f.month_field :birth_month %>
|
15
|
+
<%= f.week_field :birthday_week %>
|
16
|
+
<%= f.url_field :favorite_url %>
|
17
|
+
<%= f.number_field :age %>
|
18
|
+
<%= f.range_field :years_of_experience %>
|
19
|
+
<%= f.password_field :password %>
|
20
|
+
<%= f.radio_button :preferred_phone_os, :iphone %>
|
21
|
+
<%= f.radio_button :preferred_phone_os, :android %>
|
22
|
+
<%= f.fields_for :parents do |parf| %>
|
23
|
+
<%= parf.text_field :name %>
|
24
|
+
<%= parf.text_area :job %>
|
25
|
+
<% end %>
|
26
|
+
<%= f.fields_for :pet do |petf| %>
|
27
|
+
<%= petf.text_field :nickname %>
|
28
|
+
<%= petf.number_field :age %>
|
29
|
+
<% end %>
|
30
|
+
<% end %>
|
31
|
+
NEW_USER_FORM
|
32
|
+
)]
|
33
|
+
|
34
|
+
def new
|
35
|
+
@user = User.new
|
36
|
+
end
|
37
|
+
|
38
|
+
def auto_permit
|
39
|
+
u = params.auto_permit!(:user)
|
40
|
+
render json: u
|
41
|
+
end
|
42
|
+
|
43
|
+
def unpermitted
|
44
|
+
u = params.require(:user).permit(:name, pets: [:kind])
|
45
|
+
render json: u
|
46
|
+
end
|
47
|
+
end
|
data/test/apps/models.rb
ADDED
data/test/apps/parent.rb
ADDED
data/test/apps/pet.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require "rails"
|
2
|
+
|
3
|
+
[
|
4
|
+
#'active_record',
|
5
|
+
'active_model',
|
6
|
+
'action_controller',
|
7
|
+
'action_view',
|
8
|
+
#'action_mailer',
|
9
|
+
#'active_job',
|
10
|
+
'rails/test_unit',
|
11
|
+
#'sprockets',
|
12
|
+
].each do |framework|
|
13
|
+
begin
|
14
|
+
require "#{framework}/railtie"
|
15
|
+
rescue LoadError
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'action_view/testing/resolvers'
|
20
|
+
require 'rails/test_help'
|
21
|
+
|
22
|
+
require 'auto_strong_parameters'
|
23
|
+
|
24
|
+
require_relative './test_app'
|
25
|
+
|
26
|
+
module Rails42
|
27
|
+
class Application < Rails::Application
|
28
|
+
config.root = File.expand_path("../../..", __FILE__)
|
29
|
+
config.cache_classes = true
|
30
|
+
|
31
|
+
config.eager_load = false
|
32
|
+
config.serve_static_files = true
|
33
|
+
config.static_cache_control = "public, max-age=3600"
|
34
|
+
|
35
|
+
config.consider_all_requests_local = true
|
36
|
+
config.action_controller.perform_caching = false
|
37
|
+
|
38
|
+
config.action_dispatch.show_exceptions = false
|
39
|
+
|
40
|
+
config.action_controller.allow_forgery_protection = false
|
41
|
+
|
42
|
+
config.active_support.deprecation = :stderr
|
43
|
+
|
44
|
+
config.active_support.test_order = :sorted
|
45
|
+
|
46
|
+
config.middleware.delete "Rack::Lock"
|
47
|
+
config.middleware.delete "ActionDispatch::Flash"
|
48
|
+
config.middleware.delete "ActionDispatch::BestStandardsSupport"
|
49
|
+
config.secret_key_base = TestApp.secret_key_base
|
50
|
+
routes.append(&TestApp.routes)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
require_relative './models'
|
55
|
+
require_relative './basic_controller'
|
56
|
+
|
57
|
+
Rails42::Application.initialize!
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "rails"
|
2
|
+
|
3
|
+
[
|
4
|
+
#'active_record',
|
5
|
+
'active_model',
|
6
|
+
'action_controller',
|
7
|
+
'action_view',
|
8
|
+
#'action_mailer',
|
9
|
+
#'active_job',
|
10
|
+
'rails/test_unit',
|
11
|
+
#'sprockets',
|
12
|
+
].each do |framework|
|
13
|
+
begin
|
14
|
+
require "#{framework}/railtie"
|
15
|
+
rescue LoadError
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'action_view/testing/resolvers'
|
20
|
+
require 'rails/test_help'
|
21
|
+
|
22
|
+
require 'auto_strong_parameters'
|
23
|
+
|
24
|
+
require_relative './test_app'
|
25
|
+
|
26
|
+
module Rails52
|
27
|
+
class Application < Rails::Application
|
28
|
+
config.root = File.expand_path("../../..", __FILE__)
|
29
|
+
config.cache_classes = true
|
30
|
+
|
31
|
+
config.eager_load = false
|
32
|
+
config.serve_static_files = true
|
33
|
+
config.static_cache_control = "public, max-age=3600"
|
34
|
+
|
35
|
+
config.consider_all_requests_local = true
|
36
|
+
config.action_controller.perform_caching = false
|
37
|
+
|
38
|
+
config.action_dispatch.show_exceptions = false
|
39
|
+
|
40
|
+
config.action_controller.allow_forgery_protection = false
|
41
|
+
|
42
|
+
config.active_support.deprecation = :stderr
|
43
|
+
|
44
|
+
config.active_support.test_order = :sorted
|
45
|
+
|
46
|
+
config.middleware.delete "Rack::Lock"
|
47
|
+
config.middleware.delete "ActionDispatch::Flash"
|
48
|
+
config.middleware.delete "ActionDispatch::BestStandardsSupport"
|
49
|
+
config.secret_key_base = TestApp.secret_key_base
|
50
|
+
routes.append(&TestApp.routes)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
require_relative './models'
|
55
|
+
require_relative './basic_controller'
|
56
|
+
|
57
|
+
Rails52::Application.initialize!
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "rails"
|
2
|
+
|
3
|
+
[
|
4
|
+
#'active_record',
|
5
|
+
'active_model',
|
6
|
+
'action_controller',
|
7
|
+
'action_view',
|
8
|
+
#'action_mailer',
|
9
|
+
#'active_job',
|
10
|
+
'rails/test_unit',
|
11
|
+
#'sprockets',
|
12
|
+
].each do |framework|
|
13
|
+
begin
|
14
|
+
require "#{framework}/railtie"
|
15
|
+
rescue LoadError
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'action_view/testing/resolvers'
|
20
|
+
require 'rails/test_help'
|
21
|
+
|
22
|
+
require 'auto_strong_parameters'
|
23
|
+
|
24
|
+
require_relative './test_app'
|
25
|
+
|
26
|
+
module Rails60
|
27
|
+
class Application < Rails::Application
|
28
|
+
config.root = File.expand_path("../../..", __FILE__)
|
29
|
+
config.cache_classes = true
|
30
|
+
|
31
|
+
config.eager_load = false
|
32
|
+
config.serve_static_files = true
|
33
|
+
config.static_cache_control = "public, max-age=3600"
|
34
|
+
|
35
|
+
config.consider_all_requests_local = true
|
36
|
+
config.action_controller.perform_caching = false
|
37
|
+
|
38
|
+
config.action_dispatch.show_exceptions = false
|
39
|
+
|
40
|
+
config.action_controller.allow_forgery_protection = false
|
41
|
+
|
42
|
+
config.active_support.deprecation = :stderr
|
43
|
+
|
44
|
+
config.active_support.test_order = :sorted
|
45
|
+
|
46
|
+
config.middleware.delete "Rack::Lock"
|
47
|
+
config.middleware.delete "ActionDispatch::Flash"
|
48
|
+
config.middleware.delete "ActionDispatch::BestStandardsSupport"
|
49
|
+
config.secret_key_base = TestApp.secret_key_base
|
50
|
+
routes.append(&TestApp.routes)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
require_relative './models'
|
55
|
+
require_relative './basic_controller'
|
56
|
+
|
57
|
+
Rails60::Application.initialize!
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "rails"
|
2
|
+
|
3
|
+
[
|
4
|
+
#'active_record',
|
5
|
+
'active_model',
|
6
|
+
'action_controller',
|
7
|
+
'action_view',
|
8
|
+
#'action_mailer',
|
9
|
+
#'active_job',
|
10
|
+
'rails/test_unit',
|
11
|
+
#'sprockets',
|
12
|
+
].each do |framework|
|
13
|
+
begin
|
14
|
+
require "#{framework}/railtie"
|
15
|
+
rescue LoadError
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'action_view/testing/resolvers'
|
20
|
+
require 'rails/test_help'
|
21
|
+
|
22
|
+
require 'auto_strong_parameters'
|
23
|
+
|
24
|
+
require_relative './test_app'
|
25
|
+
|
26
|
+
module Rails61
|
27
|
+
class Application < Rails::Application
|
28
|
+
config.root = File.expand_path("../../..", __FILE__)
|
29
|
+
config.cache_classes = true
|
30
|
+
|
31
|
+
config.eager_load = false
|
32
|
+
config.serve_static_files = true
|
33
|
+
config.static_cache_control = "public, max-age=3600"
|
34
|
+
|
35
|
+
config.consider_all_requests_local = true
|
36
|
+
config.action_controller.perform_caching = false
|
37
|
+
|
38
|
+
config.action_dispatch.show_exceptions = false
|
39
|
+
|
40
|
+
config.action_controller.allow_forgery_protection = false
|
41
|
+
|
42
|
+
config.active_support.deprecation = :stderr
|
43
|
+
|
44
|
+
config.active_support.test_order = :sorted
|
45
|
+
|
46
|
+
config.middleware.delete "Rack::Lock"
|
47
|
+
config.middleware.delete "ActionDispatch::Flash"
|
48
|
+
config.middleware.delete "ActionDispatch::BestStandardsSupport"
|
49
|
+
config.secret_key_base = TestApp.secret_key_base
|
50
|
+
routes.append(&TestApp.routes)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
require_relative './models'
|
55
|
+
require_relative './basic_controller'
|
56
|
+
|
57
|
+
Rails61::Application.initialize!
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "rails"
|
2
|
+
|
3
|
+
[
|
4
|
+
#'active_record',
|
5
|
+
'active_model',
|
6
|
+
'action_controller',
|
7
|
+
'action_view',
|
8
|
+
#'action_mailer',
|
9
|
+
#'active_job',
|
10
|
+
'rails/test_unit',
|
11
|
+
#'sprockets',
|
12
|
+
].each do |framework|
|
13
|
+
begin
|
14
|
+
require "#{framework}/railtie"
|
15
|
+
rescue LoadError
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'action_view/testing/resolvers'
|
20
|
+
require 'rails/test_help'
|
21
|
+
|
22
|
+
require 'auto_strong_parameters'
|
23
|
+
|
24
|
+
require_relative './test_app'
|
25
|
+
|
26
|
+
module Rails70
|
27
|
+
class Application < Rails::Application
|
28
|
+
config.root = File.expand_path("../../..", __FILE__)
|
29
|
+
config.cache_classes = true
|
30
|
+
|
31
|
+
config.eager_load = false
|
32
|
+
config.serve_static_files = true
|
33
|
+
config.static_cache_control = "public, max-age=3600"
|
34
|
+
|
35
|
+
config.consider_all_requests_local = true
|
36
|
+
config.action_controller.perform_caching = false
|
37
|
+
|
38
|
+
config.action_dispatch.show_exceptions = false
|
39
|
+
|
40
|
+
config.action_controller.allow_forgery_protection = false
|
41
|
+
|
42
|
+
config.active_support.deprecation = :stderr
|
43
|
+
|
44
|
+
config.active_support.test_order = :sorted
|
45
|
+
|
46
|
+
config.middleware.delete Rack::Lock
|
47
|
+
config.middleware.delete ActionDispatch::Flash
|
48
|
+
config.secret_key_base = TestApp.secret_key_base
|
49
|
+
routes.append(&TestApp.routes)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
require_relative './models'
|
54
|
+
require_relative './basic_controller'
|
55
|
+
|
56
|
+
Rails70::Application.initialize!
|
data/test/apps/routes.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
class TestApp
|
2
|
+
def self.routes
|
3
|
+
-> do
|
4
|
+
get "new" => "basic#new"
|
5
|
+
post "auto_permit" => "basic#auto_permit"
|
6
|
+
post "unpermitted" => "basic#unpermitted"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.secret_key_base
|
11
|
+
'49837489qkuweoiuoqwehisuakshdjksadhaisdy78o34y138974xyqp9rmye8yrpiokeuioqwzyoiuxftoyqiuxrhm3iou1hrzmjk'
|
12
|
+
end
|
13
|
+
end
|
data/test/apps/user.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
class User
|
2
|
+
include ActiveModel::Model
|
3
|
+
|
4
|
+
attr_accessor :name, :email, :description, :phone, :dob, :lunch_time,
|
5
|
+
:confirmed_at, :birth_month, :birthday_week, :favorite_url, :age,
|
6
|
+
:years_of_experience, :password, :preferred_phone_os
|
7
|
+
|
8
|
+
def parents
|
9
|
+
@parents ||= [Parent.new]
|
10
|
+
end
|
11
|
+
|
12
|
+
def parents_attributes=(val)
|
13
|
+
@parents = Array.wrap(val)
|
14
|
+
end
|
15
|
+
|
16
|
+
def pet
|
17
|
+
@pet ||= Pet.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def pet_attributes=(val)
|
21
|
+
@pet = val
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class AutoFormParamsTest < ActionController::TestCase
|
6
|
+
setup do
|
7
|
+
@controller = BasicController.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def signature
|
11
|
+
AutoStrongParameters.verifier.generate(permitted_keys)
|
12
|
+
end
|
13
|
+
|
14
|
+
def permitted_keys
|
15
|
+
{
|
16
|
+
"user" => [
|
17
|
+
"name",
|
18
|
+
"email",
|
19
|
+
"description",
|
20
|
+
"phone",
|
21
|
+
"dob",
|
22
|
+
"lunch_time",
|
23
|
+
"confirmed_at",
|
24
|
+
"birth_month",
|
25
|
+
"birthday_week",
|
26
|
+
"favorite_url",
|
27
|
+
"age",
|
28
|
+
"years_of_experience",
|
29
|
+
"password",
|
30
|
+
"preferred_phone_os",
|
31
|
+
{
|
32
|
+
"parents_attributes"=>[
|
33
|
+
"name",
|
34
|
+
"job",
|
35
|
+
],
|
36
|
+
"pet_attributes"=>[
|
37
|
+
"nickname",
|
38
|
+
"age",
|
39
|
+
],
|
40
|
+
},
|
41
|
+
],
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_new
|
46
|
+
get :new
|
47
|
+
assert_response :ok
|
48
|
+
|
49
|
+
assert_select "form[id='new_user']"
|
50
|
+
assert_select "form[id='new_user'] input[name='#{AutoStrongParameters.asp_message_key}']" do
|
51
|
+
assert_select "[value=?]", signature
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class AutoPermitTest < ActionController::TestCase
|
6
|
+
setup do
|
7
|
+
@controller = BasicController.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def user_params
|
11
|
+
{
|
12
|
+
name: 'John',
|
13
|
+
age: '30',
|
14
|
+
pets: [
|
15
|
+
{ name: "Fluffy", kind: "dog" }
|
16
|
+
],
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def signature
|
21
|
+
AutoStrongParameters.verifier.generate(permitted_keys)
|
22
|
+
end
|
23
|
+
|
24
|
+
def message_key
|
25
|
+
AutoStrongParameters.asp_message_key
|
26
|
+
end
|
27
|
+
|
28
|
+
def permitted_keys
|
29
|
+
{ "user" => ['name', 'age', { 'pets' => ['name', 'kind'] }] }
|
30
|
+
end
|
31
|
+
|
32
|
+
# Rails 4.2 does not have the keyword API for #process et al.
|
33
|
+
def process_args(args)
|
34
|
+
if defined? Rails42
|
35
|
+
args
|
36
|
+
else
|
37
|
+
{ params: args }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_unpermitted
|
42
|
+
post :unpermitted, **process_args(user: user_params)
|
43
|
+
assert_response :ok
|
44
|
+
j = ActiveSupport::JSON.decode(response.body)
|
45
|
+
|
46
|
+
assert_equal 'John', j['name']
|
47
|
+
assert_nil j['age']
|
48
|
+
assert_nil j['pets'][0]['name']
|
49
|
+
assert_equal 'dog', j['pets'][0]['kind']
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_auto_permit
|
53
|
+
post :auto_permit, **process_args(user: user_params.merge(message_key => signature))
|
54
|
+
assert_response :ok
|
55
|
+
j = ActiveSupport::JSON.decode(response.body)
|
56
|
+
|
57
|
+
assert_equal 'John', j['name']
|
58
|
+
assert_equal '30', j['age']
|
59
|
+
assert_equal 'dog', j['pets'][0]['kind']
|
60
|
+
assert_equal 'Fluffy', j['pets'][0]['name']
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_auto_permit_incorrect_signature
|
64
|
+
post :auto_permit, **process_args(user: user_params.merge(message_key => 'abc123'))
|
65
|
+
assert_response :ok
|
66
|
+
j = ActiveSupport::JSON.decode(response.body)
|
67
|
+
|
68
|
+
assert_nil j['name']
|
69
|
+
assert_nil j['age']
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class AutoStrongParametersTest < Minitest::Test
|
6
|
+
def to_strong_params_shape(h)
|
7
|
+
AutoStrongParameters.to_strong_params_shape(h)
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_to_strong_params_shape
|
11
|
+
assert_equal ["name"], to_strong_params_shape({"name" => "Steve"})
|
12
|
+
assert_equal ["name", "age"], to_strong_params_shape({"name" => "Steve", age: 5})
|
13
|
+
assert_equal ["name", {"pet" => ["name"]}], to_strong_params_shape({"name" => "Steve", "pet" => { "name" => "Fluffy" }})
|
14
|
+
assert_equal ["name", {"pet" => ["name"]}], to_strong_params_shape({"name" => "Steve", "pet" => { "name" => "Fluffy" }})
|
15
|
+
end
|
16
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'pry'
|
4
|
+
|
5
|
+
ENV["RAILS_ENV"] = "test"
|
6
|
+
ENV['DATABASE_URL'] = 'sqlite3://localhost/:memory:'
|
7
|
+
|
8
|
+
require 'rails'
|
9
|
+
|
10
|
+
case Rails.version.slice(0, 3)
|
11
|
+
when "4.2"
|
12
|
+
require "apps/rails42"
|
13
|
+
when "5.2"
|
14
|
+
require "apps/rails52"
|
15
|
+
when "6.0"
|
16
|
+
require "apps/rails60"
|
17
|
+
when "6.1"
|
18
|
+
require "apps/rails61"
|
19
|
+
when "7.0"
|
20
|
+
require "apps/rails70"
|
21
|
+
else
|
22
|
+
raise "Un-tested version of Rails: #{Rails.version}"
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: auto_strong_parameters
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Drew Ulmer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-08-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: appraisal
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description:
|
84
|
+
email: drew@unabridgedsoftware.com
|
85
|
+
executables: []
|
86
|
+
extensions: []
|
87
|
+
extra_rdoc_files: []
|
88
|
+
files:
|
89
|
+
- README.md
|
90
|
+
- Rakefile
|
91
|
+
- lib/auto_strong_parameters.rb
|
92
|
+
- lib/auto_strong_parameters/auto_form_params.rb
|
93
|
+
- lib/auto_strong_parameters/auto_permit.rb
|
94
|
+
- lib/auto_strong_parameters/controller_permitter.rb
|
95
|
+
- lib/auto_strong_parameters/railtie.rb
|
96
|
+
- lib/auto_strong_parameters/version.rb
|
97
|
+
- test/apps/basic_controller.rb
|
98
|
+
- test/apps/models.rb
|
99
|
+
- test/apps/parent.rb
|
100
|
+
- test/apps/pet.rb
|
101
|
+
- test/apps/rails42.rb
|
102
|
+
- test/apps/rails52.rb
|
103
|
+
- test/apps/rails60.rb
|
104
|
+
- test/apps/rails61.rb
|
105
|
+
- test/apps/rails70.rb
|
106
|
+
- test/apps/routes.rb
|
107
|
+
- test/apps/test_app.rb
|
108
|
+
- test/apps/user.rb
|
109
|
+
- test/auto_form_params_test.rb
|
110
|
+
- test/auto_permit_test.rb
|
111
|
+
- test/auto_strong_parameters_test.rb
|
112
|
+
- test/test_helper.rb
|
113
|
+
homepage: https://github.com/unabridged/auto_strong_parameters
|
114
|
+
licenses:
|
115
|
+
- MIT
|
116
|
+
metadata: {}
|
117
|
+
post_install_message:
|
118
|
+
rdoc_options: []
|
119
|
+
require_paths:
|
120
|
+
- lib
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
requirements: []
|
132
|
+
rubygems_version: 3.1.6
|
133
|
+
signing_key:
|
134
|
+
specification_version: 4
|
135
|
+
summary: Automatic require and permit of Strong Paramters for your Rails forms.
|
136
|
+
test_files:
|
137
|
+
- test/auto_form_params_test.rb
|
138
|
+
- test/test_helper.rb
|
139
|
+
- test/apps/routes.rb
|
140
|
+
- test/apps/test_app.rb
|
141
|
+
- test/apps/rails52.rb
|
142
|
+
- test/apps/rails42.rb
|
143
|
+
- test/apps/basic_controller.rb
|
144
|
+
- test/apps/parent.rb
|
145
|
+
- test/apps/pet.rb
|
146
|
+
- test/apps/rails61.rb
|
147
|
+
- test/apps/models.rb
|
148
|
+
- test/apps/rails60.rb
|
149
|
+
- test/apps/rails70.rb
|
150
|
+
- test/apps/user.rb
|
151
|
+
- test/auto_strong_parameters_test.rb
|
152
|
+
- test/auto_permit_test.rb
|