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

fix: don't eager load the models if pending DB migrations #690

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

did
Copy link

@did did commented Oct 2, 2024

Context:

Rails 7 app with an existing User model.

Issue:

We update our AR model User by adding an enum named access_level (the name is not important).
So we generate a migration, define the new column (access_level) and add the enum statement in the User model.
When running the rails db:migrate command, it fails withe following message:

/Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/activerecord-7.1.3.4/lib/active_record/enum.rb:250:in `block in _enum': Undeclared attribute type for enum 'access_level'. Enums must be backed by a database column or declared with an explicit type via `attribute`. (RuntimeError)

The problem is that the ForestAdmin engine eager loads all the AR models and executes the enum class method within the models. Rails expects the column to exist in DB but since we're running the migration, well the famous egg -> chicken issue.

Solutions:

Solution 1: don't require ForestAdmin in the Gemfile and require in the application.rb file only if we're not running rails db:migrate. This involves a lot of if defined?(ForestLiana) in the code. 🙅🏻

Solution 2: don't eager load the models in the ForestAdmin engine IF there are pending migrations. 👌

Definition of Done

General

  • Write an explicit title for the Pull Request, following Conventional Commits specification
  • Test manually the implemented changes
  • Validate the code quality (indentation, syntax, style, simplicity, readability)

Security

  • Consider the security impact of the changes made

@matthv
Copy link
Member

matthv commented Oct 4, 2024

Hello @did, thank you for your contribution 👍. However we have not been able to reproduce the problem on our side. Could you share the migration and the model of your rails with us?

@did
Copy link
Author

did commented Oct 7, 2024

hey @matthv, thanks for taking the time to look at it!

Working for one of your clients, I can't disclose the code of the migration + model here.
But glad to set up a quick call.

Here is the stack trace which lead me to assume this was related to ForestAdmin but probably, it's a combination of multiple factors.

/Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/activerecord-7.1.3.4/lib/active_record/enum.rb:250:in `block in _enum': Undeclared attribute type for enum 'my_enum'. Enums must be backed by a database column or declared with an explicit type via `attribute`. (RuntimeError)
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/activerecord-7.1.3.4/lib/active_record/attributes.rb:225:in `block in attribute'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/activerecord-7.1.3.4/lib/active_record/attributes.rb:266:in `block in load_schema!'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/activerecord-7.1.3.4/lib/active_record/attributes.rb:265:in `each'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/activerecord-7.1.3.4/lib/active_record/attributes.rb:265:in `load_schema!'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/activerecord-7.1.3.4/lib/active_record/encryption/encryptable_record.rb:127:in `load_schema!'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/activerecord-7.1.3.4/lib/active_record/model_schema.rb:563:in `block in load_schema'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/activerecord-7.1.3.4/lib/active_record/model_schema.rb:560:in `synchronize'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/activerecord-7.1.3.4/lib/active_record/model_schema.rb:560:in `load_schema'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/activerecord-7.1.3.4/lib/active_record/model_schema.rb:430:in `columns'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/activerecord-7.1.3.4/lib/active_record/model_schema.rb:505:in `column_names'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/forest_liana-9.3.16/app/serializers/forest_liana/serializer_factory.rb:385:in `attributes'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/forest_liana-9.3.16/app/serializers/forest_liana/serializer_factory.rb:179:in `serializer_for'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/forest_liana-9.3.16/lib/forest_liana/bootstrapper.rb:134:in `block in create_factories'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/forest_liana-9.3.16/lib/forest_liana/bootstrapper.rb:133:in `map'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/forest_liana-9.3.16/lib/forest_liana/bootstrapper.rb:133:in `create_factories'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/forest_liana-9.3.16/lib/forest_liana/bootstrapper.rb:39:in `initialize'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/forest_liana-9.3.16/lib/forest_liana/engine.rb:106:in `new'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/forest_liana-9.3.16/lib/forest_liana/engine.rb:106:in `block in <class:Engine>'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/activesupport-7.1.3.4/lib/active_support/lazy_load_hooks.rb:94:in `block in execute_hook'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/activesupport-7.1.3.4/lib/active_support/lazy_load_hooks.rb:87:in `with_execution_control'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/activesupport-7.1.3.4/lib/active_support/lazy_load_hooks.rb:92:in `execute_hook'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/activesupport-7.1.3.4/lib/active_support/lazy_load_hooks.rb:78:in `block in run_load_hooks'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/activesupport-7.1.3.4/lib/active_support/lazy_load_hooks.rb:77:in `each'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/activesupport-7.1.3.4/lib/active_support/lazy_load_hooks.rb:77:in `run_load_hooks'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/railties-7.1.3.4/lib/rails/application/finisher.rb:93:in `block in <module:Finisher>'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/railties-7.1.3.4/lib/rails/initializable.rb:32:in `instance_exec'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/railties-7.1.3.4/lib/rails/initializable.rb:32:in `run'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/railties-7.1.3.4/lib/rails/initializable.rb:61:in `block in run_initializers'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/3.3.0/tsort.rb:231:in `block in tsort_each'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/3.3.0/tsort.rb:353:in `block (2 levels) in each_strongly_connected_component'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/3.3.0/tsort.rb:434:in `each_strongly_connected_component_from'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/3.3.0/tsort.rb:352:in `block in each_strongly_connected_component'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/3.3.0/tsort.rb:350:in `each'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/3.3.0/tsort.rb:350:in `call'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/3.3.0/tsort.rb:350:in `each_strongly_connected_component'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/3.3.0/tsort.rb:229:in `tsort_each'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/3.3.0/tsort.rb:208:in `tsort_each'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/railties-7.1.3.4/lib/rails/initializable.rb:60:in `run_initializers'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/railties-7.1.3.4/lib/rails/application.rb:426:in `initialize!'
	from /Users/johndoe/Documents/my-api-project/config/environment.rb:4:in `<main>'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/3.3.0/bundled_gems.rb:75:in `require'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/3.3.0/bundled_gems.rb:75:in `block (2 levels) in replace_require'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/bootsnap-1.18.4/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/zeitwerk-2.6.18/lib/zeitwerk/kernel.rb:34:in `require'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/spring-4.2.1/lib/spring/application.rb:112:in `preload'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/spring-4.2.1/lib/spring/application.rb:171:in `serve'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/spring-4.2.1/lib/spring/application.rb:153:in `block in run'
	from <internal:kernel>:187:in `loop'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/spring-4.2.1/lib/spring/application.rb:147:in `run'
	from /Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/gems/3.3.0/gems/spring-4.2.1/lib/spring/application/boot.rb:25:in `<top (required)>'
	from <internal:/Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>:136:in `require'
	from <internal:/Users/johndoe/.rbenv/versions/3.3.5/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>:136:in `require'
	from -e:1:in `<main>'

thanks!

@matthv
Copy link
Member

matthv commented Oct 8, 2024

Hello @did
I have tested on different version of rails (7.0.8 & 7.1.4) and I still can't reproduce the bug.
However, when I do a search for this error "Undeclared attribute type for enum ..." I get quite a few results and possibly a bug on rails. see: rails/rails@b5fe9ec

Could you update your rails to see if the problem persists ?

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.

2 participants