Closed dmke closed 1 month ago
@dmke thanks for a detailed explanation + steps to reproduce.
I think you're 100% right on the cause + fix. Would you mind putting up a PR for this? I think just that change itself should be sufficient for supporting both the direct gem invocation (bundle exec annotaterb models
) and hooking to db rake task invocation (bin/rails db:migrate
).
Would you mind putting up a PR for this?
Will do, just don't know when :)
Will do, just don't know when :)
No worries, whenever you have a moment it would be appreciated. It doesn't have to be much more than just the conditional change you proposed. It's nice for me when other folks feel empowered to add PRs :).
I'm revisiting this issue now that I'm done with refactors. The more that I think about this, the more I'm beginning to wonder why AnnotateRb::RakeBootstrapper
needs to load all the rake tasks at all.
I'll do some more investigation but that piece of code is 15+ years old: https://github.com/ctran/annotate_models/commit/2813dbd9f6e7f18449ff8c9c753f439ca22e5e47
The call
method's primary goals seem to be:
Loading rake
was just a means to the end of loading the defaults defined in lib/tasts/annotate_models.rake
, which this fork has superseded by a YAML file.
I believe, the call
method could be condensed to:
def call(_)
require_relative "./config/environment.rb" if File.exist?("./config/environment.rb")
end
since ActiveSupport will already be loaded unconditionally in lib/annotate_rb.rb
.
I'll try to experiment with that later.
Thanks for trying to dig into this. I spent some time today and will give it another go later this week, but I realized I was mistaken by what actually happens.
In the commit I referenced above, it actually loads the annotaterb/lib/annotate_rb/tasks/annotate_models_migrate.rake
and not lib/tasks
file in the Rails app.
--
Unless I'm mistaken, there's 3 ways to run AnnotateRb with the context of a Rails app:
bundle exec annotaterb models
, assumes annotaterb gem is in the Gemfileannotaterb models
, assumes annotaterb gem is installed but not necessarily specified in GemfileI don't usually test 2) but I believe there might be setups that do this, especially if there's Rails engines. I'll try and understand the behavior of the RakeBootstrapper
in all 3 contexts and report my findings.
@dmke Okay, I think I got a better sense of how things work given those 3 different entry points. The AnnotateRb::RakeBootstrapper
only needs to be called if run using methods 1 or 2 (bundle exec annotaterb
or annotaterb
). If AnnotateRb is triggered through db migrations (method 3), then the Rails context already exists.
annotaterb models
Gem.activate_bin_path
exe/annotaterb
AnnotateRb::Runner
AnnotateRb::Bootstrapper
Rakefile
, if it existsRails.application.load_tasks
(in the Rakefile), tells Rails to load Rake tasks for the main appThere's no double loading of codegen.rake
bundle exec annotaterb models
Hooked into rake db tasks (bin/rails db:migrate
)
bin/rails
binstubdb:migrate
)Rakefile
lib/tasks/annotate_rb.rake
)AnnotateRb::Core.load_rake_tasks
annotaterb/lib/annotate_rb/tasks/annotate_models_migrate.rake
annotaterb/lib/annotate_rb/tasks/annotate_models_migrate.rake
: triggers AnnotateRb::Runner
AnnotateRb::Runner
calls AnnotateRb::RakeBootstrapper
which loads the Rails app's Rakefile (again), leading to double loading of rake tasks in lib/tasks
I released a new gem version, 4.10.2
, which contains your change. Let me know if you have any issues.
Thanks, will try later!
So, it took a moment, but it works as expected.
Thanks again!
I have some Rake files, which define some constants. When running
bin/rails db:migrate
, the output is flooded with warnings of already defined constants.This doesn't happen when calling
bundle exec annotaterb models
.Commands
Reproduction
rails new --minimal --api
or similar)rails g model User name email:unique
) (not sure if this is necessary)Create a
lib/tasks/codegen.rake
(the actual name is not relevant, it must end in.rake
though):bin/rails db:{create,migrate}
). Observe no warning.annotaterb
, configureskip_on_db_migrate: false
.bin/rails db:migrate
). Observe warnings.Breakdown
Adding a
puts caller
before theCodegen::RAILS_ROOT
constant reveals the following:The culprit likely lies in
rake_bootstrapper.rb
(omitting some details), which loads the Rakefile unconditionally if it exists:AFAICT, the reason for this is to ensure that the
environment
task will be defined (throughRails.application.load_tasks
in standard Rails-generated Rakefiles).We could eliminate the warning by checking whether that task is defined:
This works with both
bin/rails db:migrate
andbundle exec annotaterb models
. I'm not sure whether are other forms of invocations, so this might need a more thorough testing.Version