-
Notifications
You must be signed in to change notification settings - Fork 71
THREESCALE-12434: Migrate from protected attributes to strong parameters - Part 3 #4255
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: strong-params-part2
Are you sure you want to change the base?
Changes from all commits
7294df5
9f50fb3
2bda4f2
82cecfe
bae4daa
7ec8391
0264807
5c8e3a5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -33,7 +33,11 @@ def backend_api_config | |||||
| end | ||||||
|
|
||||||
| def backend_api | ||||||
| @backend_api ||= backend_api_configs.first&.backend_api || account.backend_apis.build(system_name: service_system_name, name: "#{service_name} Backend", description: "Backend of #{service_name}") | ||||||
| # Return early if we already have a persisted backend_api | ||||||
| return @backend_api if @backend_api&.persisted? | ||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This issue with This commit contains a solution that Claude provided, and I'm putting his explanation below. I am not convinced or happy with this though, and I find the whole lazy building messy... I think we need to review the behavior again, and try to get rid of any lazy building, because it just makes things complicated and error-prone.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. BackendApiProxy Cache Issue After Removing protected_attributes_continuedProblemAfter removing the
Root CauseThe behavioral difference is caused by How BackendApiProxy caches a backend_apiWhen a Service is created,
@backend_api ||= backend_api_configs.first&.backend_api ||
account.backend_apis.build(system_name: ..., name: ..., description: ...)Since no What changed: inverse_of behaviorThe Proxy model has On master (with protected_attributes_continued)The gem subtly breaks This means the stale On the branch (without the gem)
Later calls to EvidenceTracing Master: Branch: Impact on Production CodeThe main production code path that uses def save!(params)
@service.save! # triggers create_default_proxy -> caches stale @backend_api_proxy
...
save_default_backend_api(params) # calls backend_api_proxy.update!(params)
end
Other production code paths access backend_api through FixCode fix:
|
||||||
|
|
||||||
| # Try to get backend_api from backend_api_configs, or keep the memoized unpersisted one, or build a new one | ||||||
| @backend_api = backend_api_configs.first&.backend_api || @backend_api || build_backend_api | ||||||
| end | ||||||
|
|
||||||
| def update!(attrs = {}) | ||||||
|
|
@@ -52,6 +56,18 @@ def update(attrs = {}) | |||||
| rescue ActiveRecord::RecordInvalid | ||||||
| false | ||||||
| end | ||||||
|
|
||||||
| private | ||||||
|
|
||||||
| def build_backend_api | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| # Build without adding to association to avoid polluting it with unpersisted records | ||||||
| BackendApi.new( | ||||||
| account: account, | ||||||
| system_name: service_system_name, | ||||||
| name: "#{service_name} Backend", | ||||||
| description: "Backend of #{service_name}" | ||||||
| ) | ||||||
| end | ||||||
| end | ||||||
|
|
||||||
| def backend_api_proxy | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,9 +11,8 @@ def initialize(provider) | |
| def for(klass) | ||
| columns = klass.column_names | ||
| defined = fields_definitions.by_target(klass.name.underscore).map(&:name) | ||
| protected = klass.protected_attributes.to_a | ||
|
|
||
| ((columns + defined) - protected).uniq | ||
| (columns + defined).uniq | ||
| end | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bob could not grep this method used anywhere. I could not ripgrep that as well. Maybe we can remove this method? Or if it is still used somewhere, perhaps we should omit the non-assignable attributes? I'm running some tests and they don't indicate that the method does anything: So perhaps it is dead code to be removed. |
||
|
|
||
| protected | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -178,8 +178,7 @@ def validate_expiration_date | |||||||
| end | ||||||||
|
|
||||||||
| def generate_if_missing | ||||||||
| return if persisted? | ||||||||
| return if @plaintext_value.present? | ||||||||
| return if value.present? | ||||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was required due to the removal of the The part that got broken is: porta/test/integration/user-management-api/base_controller_test.rb Lines 133 to 135 in 0264807
and, as a result, the tests that were relying on this So, apparently, the gem was overriding the After removing the gem, the execution stack consists of the standard I think checking for
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jlledom can you please take a look at this change and let me know if you think it's fine? All tests are passing 🙌
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've been checking and this looks correct to me. Even better than before. |
||||||||
|
|
||||||||
| @plaintext_value = self.class.random_id | ||||||||
| self.value = self.class.compute_digest(@plaintext_value) | ||||||||
|
|
||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,10 +32,8 @@ def diff(other) | |
| end | ||
|
|
||
| def revert_attributes | ||
| accessible = template.class.accessible_attributes.delete('draft').add('updated_at').add('updated_by') | ||
|
|
||
| accessible << state.to_s | ||
| attributes.slice *accessible | ||
| accessible = [:updated_at, :updated_by, state.to_s] | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't remember how exactly I came up with this replacement, but I think it was just debugging and checking what fields were actually available there.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. According to Claude, I broke this method in this commit: 33b70d3 However, after my changes it was effectively doing the same you do in this commit, just returning So I guess:
There are no tests for
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm... I don't see changes to that file in the commit you mentioned 🤔
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In that commit, I removed the protected attributes for the - attr_accessible :provider, :draft, :liquid_enabled, :handlerAfter that change,
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I, I see, right, thank you for the explanation! Yeah, it rings a bell now, indeed, that
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you think the versioning feature is working fine? didn't I break it?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When I tried, it seemed to be doing the right thing.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A good engineer knows how to make mistakes! |
||
| attributes.slice(*accessible) | ||
| end | ||
|
|
||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,14 +10,15 @@ def self.fetch_with_retry!(options, &block) | |
| retries = 0 | ||
|
|
||
| begin | ||
| MailDispatchRule.find_or_create_by!(options, &block) | ||
| # Use find_by + create! directly to avoid transaction wrapper from create_or_find_by! | ||
| # This preserves the old behavior from protected_attributes_continued gem | ||
| # where records created in the block are committed even if the outer create fails | ||
| find_by(options) || create!(options, &block) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure whether this is the right thing to do... This is basically keeping the old behavior. The test that is failing without it is: It verifies (how I understand it) that if a race condition occurs when creating With no code change, the test fails with the error: So, with With the gem removed, the ActiveRecord method is being called directly: create_or_find_by! wraps the createion in a transaction, so if anything fails within it, all created objects get rolled back.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, honestly, my feeling is that it's that the test doesn't represent what would be happening in the production code. If the object is created in two different places, then Rails' standard So, we probably don't need this loop, and the race condition simulation should be done in a different way. However, I don't want to risk it, because I don't quite understand the possible use case, so I decided to just keep the previous behavior.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I don't remember all details now, but I think any changes there will not have any effect.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I found this: https://redhat.atlassian.net/browse/THREESCALE-11825
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good, thank you for the info!
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we remove the class then? No need for a migration, we can add the migration in the JIRA. But why keep this code at all? |
||
| rescue ActiveRecord::RecordNotUnique | ||
| if retries > 10 | ||
| raise | ||
| else | ||
| retries += 1 | ||
| retry | ||
| end | ||
| raise if retries > 10 | ||
|
|
||
| retries += 1 | ||
| retry | ||
| end | ||
| end | ||
| end | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about adding a comment like: