THREESCALE-12434: Migrate from protected attributes to strong parameters - Part 2#4249
THREESCALE-12434: Migrate from protected attributes to strong parameters - Part 2#4249mayorova wants to merge 8 commits into
Conversation
jlledom
left a comment
There was a problem hiding this comment.
Some comments come from the other PR. Also, I still see a lot of
38e277c to
db25ecf
Compare
| @account_params ||= begin | ||
| defined_fields_names = buyer_account.defined_fields_names | ||
| allowed_attrs = defined_fields_names - %w(billing_address) + %w(name) | ||
| nested_params = { extra_fields: buyer_account.defined_extra_fields_names } |
There was a problem hiding this comment.
So, this is different from other API controller, which have only plain parameters, i.e. not nested under extra_fields.
I only did this because there was an existing test in test/integration/admin/api/accounts_controller_test.rb which was passing extra params in this way:
params: update_params.merge(extra_fields: { my_field: 4 })
I also added a check that plain parameters would also work.
Now I'm not sure if other API controllers need to accept both ways too 🤔
a676b21 to
8b5a6de
Compare
0b8ead4 to
6c69623
Compare
498f50b to
706cacb
Compare
a08b299 to
d3304a9
Compare
e2771a2 to
1abbc5c
Compare
❌ 30 blocking issues (32 total)
|
279e452 to
7981703
Compare
4b5523f to
5f946c2
Compare
24a8494 to
d30e446
Compare
7d4be7e to
8554802
Compare
8554802 to
14797a9
Compare
|
|
||
| def buyer | ||
| @buyer ||= @provider.buyers.build do |account| | ||
| # We need to get all the account params to run the spam check |
There was a problem hiding this comment.
This was indeed added explicitly in this PR: https://github.com/3scale/porta/pull/3215/changes
However, later the implementation of the spam check was changed, and this method became dead code: a798bc0
| def test_defined_fields_names | ||
| field1 = mock('field', name: 'field1') | ||
| field2 = mock('field', name: 'field2') | ||
| model = Model.new | ||
| model.stubs(:defined_fields).returns([field1, field2]) | ||
| assert_same_elements %w[field1 field2], model.defined_fields_names | ||
| end | ||
|
|
||
| def test_defined_extra_fields_names | ||
| extra_field = mock('field', name: 'extra') | ||
| builtin_field = mock('field') | ||
| model = Model.new | ||
| model.stubs(:defined_fields).returns([extra_field, builtin_field]) | ||
| model.stubs(:defined_builtin_fields).returns([builtin_field]) | ||
| assert_equal %w[extra], model.defined_extra_fields_names | ||
| end | ||
|
|
||
| def test_defined_builtin_fields_names | ||
| field1 = mock('field', name: 'field1') | ||
| field2 = mock('field', name: 'field2') | ||
| model = Model.new | ||
| model.stubs(:defined_builtin_fields).returns([field1, field2]) | ||
| assert_same_elements %w[field1 field2], model.defined_builtin_fields_names | ||
| end |
There was a problem hiding this comment.
feels like all these are redundant in the presence of test_provider_fields
There was a problem hiding this comment.
Well, I think the tests are not redundant, because each one tests a different method.
However, now I'm thinking - why didn't I use defined_fields_names_for everywhere instead of the alternatives?..
I guess the reason is that at first it hadn't occurred to me. I was relying on the existing defined_fields_names and similar, whose implementation is actually more complex, because it:
- requires a properly initialized instance - which is a bit inconvenient, and made me build the new instance of objects with proper associations before being able to derive the list of defined fields
- includes calculating the
fields_definitions_source_rootetc.
It makes me think - should I refactor the whole PR to use this simpler defined_fields_names_for(class_name)? 🤔
There was a problem hiding this comment.
overlooked the actual method names, too late when I was looking at these :)
There was a problem hiding this comment.
should I refactor the whole PR to use this simpler defined_fields_names_for(class_name)?
If not too intrusive, it would be great but can go in another PR as well.
| test "index shows users list" do | ||
| get :index | ||
| assert_response :success | ||
| end | ||
|
|
||
| test "edit shows user form" do | ||
| get :edit, params: { id: @member_user.id } | ||
| assert_response :success | ||
| end |
There was a problem hiding this comment.
I assume we have some cucumberf for this. What are we testing? nothing_raised 😅 ?
There was a problem hiding this comment.
Pretty much 😉
I think it doesn't hurt, and it's good practice to test every action of the controller.
Now, could these tests be more extensive (e.g. assert something more) - of course. But I think it's better to have a status check than not have the test at all. I'll try to add a couple of more assertions (e.g. that the drop is assigned).
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## strong-params-part1 #4249 +/- ##
=======================================================
+ Coverage 88.98% 89.09% +0.11%
=======================================================
Files 1751 1750 -1
Lines 44108 44104 -4
Branches 686 686
=======================================================
+ Hits 39249 39294 +45
+ Misses 4843 4794 -49
Partials 16 16 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
| def signup_user! | ||
| Account.transaction do | ||
| SignupService.create(**signup_service_params(account_params, user_params)) do |signup_result| | ||
| @signup_service.create(account_params:, user_params: user_params.merge(signup_type: :minimal)) do |signup_result| |
There was a problem hiding this comment.
Bob said that previously signup_type: :new_signup was set by service while now it is set to minimal. Is this a valid concern?
| @buyer.reload | ||
| assert_equal "stuff", @buyer.extra_fields["some_extra_field"] | ||
| assert_equal 33, @buyer.vat_rate | ||
| assert_equal 33.0, @buyer.vat_rate.to_f |
There was a problem hiding this comment.
| assert_equal 33.0, @buyer.vat_rate.to_f | |
| assert_equal BigDecimal('33'), @buyer.vat_rate |
| manager_without_validation.account.expects(:validate_fields!).never | ||
| manager_without_validation.user.expects(:validate_fields!).never | ||
| manager_without_validation.create(**signup_params, validate_fields: false) | ||
| end |
There was a problem hiding this comment.
just a nit, this is much better 2 tests
| ## op.parameters.add :name => "name", :description => "Name of the application to be created.", :dataType => "string", :allowMultiple => false, :required => true, :paramType => "query" | ||
| ## op.parameters.add :name => "description", :description => "Description of the application to be created.", :dataType => "string", :allowMultiple => false, :required => true, :paramType => "query" | ||
| # | ||
|
|
There was a problem hiding this comment.
the removed comment contains useful information that params are required, types, etc. Should we remove it?
|
|
||
| def plan_id | ||
| @plan_id ||= params.require(:cinstance).permit(:plan_id).tap { |plan_params| plan_params.require(:plan_id) }[:plan_id] | ||
| @plan_id ||= cinstance_params.require(:plan_id) |
There was a problem hiding this comment.
After interrogation, Bob thinks that this change is potentially unsafe:
│ Old code (SAFE): │
│ 1 @plan_id ||= params.require(:cinstance).permit(:plan_id).tap { | │
│ plan_params| plan_params.require(:plan_id) }[:plan_id] │
│ - .permit(:plan_id) filters out arrays/hashes, only allowing scalar │
│ values │
│ - Result with plan_id: [1,2,3] → returns empty {}, then [:plan_id] │
│ returns nil │
│ │
│ New code (POTENTIALLY UNSAFE): │
│ 1 @plan_id ||= cinstance_params.require(:plan_id) │
│ - require(:plan_id) does NOT filter arrays - it just checks the key │
│ exists │
│ - Result with plan_id: [1,2,3] → returns the array [1, 2, 3]
Maybe not really, because plan_id used in #find shouldn't cause real troubles but still better to make sure we get a proper value or no value.
|
|
||
| module Provider | ||
| def provider_builds_application_for(buyer, application_plan, application_attrs = {}, service_plan = nil) | ||
| def provider_builds_application_for(buyer, application_plan, service_plan = nil, application_attrs: {}) |
There was a problem hiding this comment.
If we stopped using application_attrs as I see in app/controllers/api/applications_controller.rb and app/controllers/buyers/applications_controller.rb, why don't we remove it altogether? Since the method signature changed so much, there shouldn't be any hidden users that we would need backward compatibility for. As well it will be harder to remove this later as one will suspect existing users.
What this PR does / why we need it:
This is part 2 of the migration from protected attributes to strong parameters. See the first part in #4248
Protected attributes is an old Rails feature which was deprecated a long time ago. We were using protected_attributes_continued gem to keep it working, but now it's also discontinued and does not support Rails 7+, so it's a blocker for upgrading to Rails 7.2 for us.
This Part 2 handles the models that can have custom attributes through FieldsDefinitions - Account, User, Cinstance.
Which issue(s) this PR fixes
https://redhat.atlassian.net/browse/THREESCALE-12434
Verification steps
All tests should pass, and all features should work as before.
Special notes for your reviewer: