Skip to content
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

THREESCALE-11448: Upgrade to Rails 7.0 #3945

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open

THREESCALE-11448: Upgrade to Rails 7.0 #3945

wants to merge 23 commits into from

Conversation

mayorova
Copy link
Contributor

@mayorova mayorova commented Nov 15, 2024

What this PR does / why we need it:

Upgrading to Rails 7.0 to keep our stack up-to-date.

Which issue(s) this PR fixes

https://issues.redhat.com/browse/THREESCALE-11448

Verification steps

Everything should work.

Special notes for your reviewer:

References:

Additional references:
https://dev.to/hassanahmed/enabling-rails-70s-new-framework-defaults-hkb

@mayorova mayorova force-pushed the rails70 branch 2 times, most recently from 11a0b23 to 636ab7e Compare November 21, 2024 15:45
.circleci/config.yml Outdated Show resolved Hide resolved
@mayorova mayorova force-pushed the rails70 branch 2 times, most recently from 59ac224 to 86612ed Compare November 22, 2024 11:00
jlledom
jlledom previously approved these changes Nov 27, 2024
@jlledom
Copy link
Contributor

jlledom commented Nov 27, 2024

Ready to deploy!


query(path, details, details[:formats], locals, cache: !!key)
# force just liquid format and set an empty prefix
super(name, '', partial, details.merge(handlers: [:liquid]), key, locals)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain this? In particular it is not clear why do we force an empty prefix while previously the method used the prefix passed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not very clear to me either 😅

Basically, it has to do with the structure of the template files... We have some "shared" template files that are loaded from the file system, if they are not present in the provider's CMS, and as they are shared, they are not prefixed with the prefix, corresponding to the controller.

I actually tried removing this FallbackResolverNoPrefix class, but had some templates not being loaded.

For example, there is a template lib/developer_portal/app/views/developer_portal/_submenu.html.liquid, which is kind of "shared", and can be included as a partial in different templates. And in this case, we need to remove the prefix that the controller adds (e.g. prefix: "login" for the LoginController) to get the template resolved.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. Thanks I couldn't figure out how id it work in the past so that's why I asked. Could it have been related to the default path value? Anyway, I'm fine with it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I guess they are related in the sense that the path is constructed as: "path" + "prefix" + "name", so all of the values should be correct for the right template to be found.

@@ -8,19 +8,8 @@ def initialize(path = DeveloperPortal::VIEW_PATH)
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we also remove this constructor? Or the default value is important? Why is default value not important with FallbackResolverNoPrefix?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think provided path is needed in the constructor. In FallbackResolverNoPrefix not that it's not important, but it's just that it inherits from FallbackResolver.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The FileSystemResolver has

def initialize(path)

So the path argument exists. The difference is that we add a default value. So the question is whether we need this default value here as well in FallbackResolverNoPrefix.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, what I mean is that as FallbackResolverNoPrefix is a subclass of FallbackResolver, it inherits that constructor, and it already has that default value for path.

# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
ActiveSupport.on_load(:action_controller) do
wrap_parameters format: []
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess not needed anymore but just to confirm.


ActiveSupport.on_load(:active_record) do
ActiveRecord::Base.include ThreeScale::HasMoney
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😮 this might have been an overlook previously causing ActiveRecord to be loaded prematurely 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? The code that references ActiveRecord was not being executed until ActiveSupport was loaded

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$ RAILS_ENV=test bundle exec rake ci:db:ready db:create
Calling `DidYouMean::SPELL_CHECKERS.merge!(error_name => spell_checker)' has been deprecated. Please call `DidYouMean.correct_error(error_name, spell_checker)' instead.
Connected to mysql2://[email protected]/systemdb0
rake aborted!
NameError: uninitialized constant ThreeScale::HasMoney

  ActiveRecord::Base.include ThreeScale::HasMoney
                                       ^^^^^^^^^^
Did you mean?  Hashery
/home/dmayorov/Projects/3scale/porta/config/initializers/money.rb:4:in `block in <main>'
/home/dmayorov/Projects/3scale/porta/config/initializers/money.rb:3:in `<main>'
/home/dmayorov/Projects/3scale/porta/config/environment.rb:8:in `<main>'
/home/dmayorov/.asdf/installs/ruby/3.1.5/bin/bundle:25:in `load'
/home/dmayorov/.asdf/installs/ruby/3.1.5/bin/bundle:25:in `<main>'
Tasks: TOP => db:create => db:load_config => environment
(See full trace by running task with --trace)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I revert this change, everything works fine for me, also db:create.

I don't know why is failing for you but OK. I think wrapping the ActiveSupport.on_load(:active_record) block under to_prepare can lead it to be executed multiple times, once after every change in the code, when in development.

However I don't think its a big issue because:

  1. After every change in the code, a new callback will be added to be executed when :active_record is loaded, but I'm not sure ActiveRecord is loaded after every code change as well, I'd say it doesn't, so in the worst case you would end up with a stack of callbacks in memory which will never be called.
  2. Even if the callbacks are called, I assume ActiveRecord::Base.send(:include, ThreeScale::HasMoney) is idempotent, ActiveRecord::Base will end up having ThreeScale::HasMoney just once in its ancestors.

So I would ask you to revert the changes like I did, to verify it fails again for you, since apparently it works for me. That would be ideal because we could avoid having to_prepare and on_load nested calls. If it keeps failing for you, I'd say what you have now is good enough.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Retesting is fine. But the thing is that ThreeScale::HasMoney should be reloaded on code reload. So it may disappear from ActiveRecord::Base and not readded. That's why it looks correct to have it wrapped in to_prepare.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If ThreeScale::HasMoney changes, Zeitwerk will reload it the first time it's accessed again, but I'm not sure how true is that for modules included from libraries. Anyway, good to leave it there.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

app/lib/three_scale/has_money.rb, it is not in lib/

I'm fine if it works either way but I though any code relying on app/ in initializers has to be within to_prepare. It's a tricky question.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By "libraries" I meant ActiveRecord::Base

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I revert this change, everything works fine for me, also db:create.

I don't know why is failing for you but OK.
So I would ask you to revert the changes like I did, to verify it fails again for you, since apparently it works for me. That would be ideal because we could avoid having to_prepare and on_load nested calls. If it keeps failing for you, I'd say what you have now is good enough.

That's very strange that it works for you. I already retested it twice I think, always with the same result. And also, in CircleCI it fails with the same error. So, maybe you have something magical in your local setup 🤔

I think wrapping the ActiveSupport.on_load(:active_record) block under to_prepare can lead it to be executed multiple times, once after every change in the code, when in development.

However I don't think its a big issue because:

  1. After every change in the code, a new callback will be added to be executed when :active_record is loaded, but I'm not sure ActiveRecord is loaded after every code change as well, I'd say it doesn't, so in the worst case you would end up with a stack of callbacks in memory which will never be called.
  2. Even if the callbacks are called, I assume ActiveRecord::Base.send(:include, ThreeScale::HasMoney) is idempotent, ActiveRecord::Base will end up having ThreeScale::HasMoney just once in its ancestors.

Actually, rechecking this doc I understand that ThreeScale::HasMoney should not be reloadable, so I'll actually move it from app/lib to lib, and this way it works without being in to_prepare.

# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
# Turn false under Spring and add config.action_view.cache_template_loading = true.
config.cache_classes = true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
config.cache_classes = true
config.cache_classes = !Kernel.const_defined?(:Spring)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please explain?
Basically, I applied the new defaults for the environment files.

And... we don't even use spring, do we?... 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If spring is defined, then we don't cache classes as explained in the comment. Just make it automatic. Yeah, no Spring. I think we had it a few years ago still. Not sure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, if we ever do use it again, I'd jsut change the config, as this comment instructs:

Turn false under Spring and add config.action_view.cache_template_loading = true.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using spring is a personal decision IMO. But whatever, not important.

@@ -94,7 +94,7 @@
if defined?(Bullet)
Bullet.enable = true
Bullet.bullet_logger = true
Bullet.raise = true
Bullet.raise = false # FIXME: disable
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

were failures a lot? We need to check this before merging but perhaps better to get things ready and then investigate the N+1 issues

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, there were a lot of failures, so I temporarily disabled exceptions just to move forward, and the plan is to come back to it later.

@mayorova mayorova force-pushed the rails70 branch 2 times, most recently from 797c022 to 439d9c4 Compare December 20, 2024 12:27
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this file can be removed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, this was left accidentally. Thanks for catching!

mayorova and others added 22 commits January 8, 2025 13:03
Remove irrelevant comment
Add a note for 'raise_on_missing_translations' config

Fix unit tests
DEPRECATION WARNING: Rails 7.0 has deprecated Enumerable.sum in favor of Ruby's native implementation available since 2.4. Sum of non-numeric elements requires an initial argument. (called from timeline_data at /home/dmayorov/Projects/3scale/porta/app/controllers/provider/admin/dashboard/widget_controller.rb:31)
…g = true`

Message:Couldn't find Cinstance with [WHERE `cinstances`.`type` = ? AND `cinstances`.`user_account_id` = ?] (ActiveRecord::RecordNotFound)
/opt/ci/project/vendor/bundle/ruby/3.1.0/gems/activerecord-7.0.8.6/lib/active_record/relation/finder_methods.rb:378:in `raise_record_not_found_exception!'
/opt/ci/project/vendor/bundle/ruby/3.1.0/gems/activerecord-7.0.8.6/lib/active_record/relation/finder_methods.rb:153:in `first!'
/opt/ci/project/app/models/account/provider_methods.rb:157:in `provider_key'
/opt/ci/project/app/lib/backend/model_extensions/service.rb:20:in `update_backend_service'

Remove reset in #provider_key and fix tests
FIXME: temporarily disable some Account associations for tenant ID checker

supercede e415673 fixing tenant integrity check
jlledom
jlledom previously approved these changes Jan 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants