-
Notifications
You must be signed in to change notification settings - Fork 21.4k
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
application controller (via activeadmin) is not reloaded when modified in dev mode #12195
Comments
Does it happen without activeadmin, or have you noticed this with any other extension? Maybe they are doing something on the reloading code on their side? |
It does not happen with regular app/controllers. I haven't checked other gems with controllers that inherit from application controller. ActiveAdmin controllers are generated on startup/demand. I am not clear on how const unloading/reloading works with inheritance, when the base changes does Rails need to unload all subclasses? I suppose that if it does, it's impossible to unload and reload controllers that are not file based. |
If it doesn't happen without ActiveAdmin, then it's not our bug, it's theirs. You should file a bug over on their tracker. |
How does rails modified unloading/reloading handle inheritance, i.e. when a base class changes, does it need to unload all subclasses? I'll investigate at some point, but hopefully someone knows. I think the answer to this determines whether this scenario can be expected to work at all. |
@fxn is the master of that, but I believe it's here? https://github.com/rails/rails/blob/master/activesupport/lib/active_support/dependencies.rb |
@steveklabnik correct. @bughit I would need to dig into it, but this smells like a stale class object being cached. If there was (I am speculating) an ActiveAdmin controller that inherited from You would normally want to force redefining that admin controller so that the evaluation of the |
@fxn, from what you wrote, it sounds like the answer to my question:
is yes? So rails also unloads controllers from gems? And then reloads them? It's able to do that? And if these controllers are not in files but are dynamically constructed on startup (as I believe ActiveAdmin controllers are) then this can't work at all? Or does activeadmin need to do something to make this work? |
Active Support cannot in general unload subclasses blindly, because it is out of your control how they were loaded and it could be the case that they are not going to be redefined at all in the next request. Also, unless you go via Autoloaded subclasses are going to be wiped as any other constant. The key point is that in general, you just cannot have autoloaded ancestors in a regular non-autoloaded class. Can you point to the place where ActiveAdmin defines these controllers? |
I am still not clear on the general strategy. Experimentally it appears that if you modify a base controller (applicationcontroller), the subclasses that are part of project (app/controllers) are reloaded on the next request. How's that accomplished? I am assuming that subclasses of the modified controller are found and unloaded, is that not the case? And if the subclasses are not part of the project, are they just left left alone? Is that what accounts for the behavior I reported? What I am trying to understand is, given the current modified reloading strategy/algorithm, is current behavior expected and unavoidable, or is there something gems with controllers need to do to make reloading possible? The controller invloved in /admin/login is: Other activeadmin controllers: There may be others. |
The strategy is the following: Active Support keeps track of constants that have been autoloaded. When a change is detected in the files in development mode (depends on Since the constants are no longer there, in the next request they are autoloaded again on demand and classes are thus reloaded. So, controllers are reloaded just because their constants were autoloaded and then wiped, regardless of their relationship with If you'd like to understand a little better how this works you could watch this talk by such an eloquent and breathtakingly handsome speaker! In the examples you pointed to, I don't really see autoloaded constants, right? |
Class reloading only happens for constants autoloaded by Active Support. Active Admin defines those constants using I see that if you follow up the hierarchy you end up in controllers from inherited_resources that inherit from In principle what Active Admin would need to do is to uniformily delegate constant autoloading to AS dependencies for classes that inherit from AS-autoloaded classes. But that is a conjecture from a quick read of the source code, let me play a little bit with it and confirm (or deny!). After BaRuCo though. |
Its filepath needs to be reachable through In this case it should be a located in Basically you need to behave exactly the same as if the If you want an example, you can have a look at Tolk it has controllers that are autoloaded (and auto-unloaded) by Rails. |
…directory In order to get files automatically reloaded in Rails, these files should be under `ActiveSupport::Dependencies.autoload_paths` directory. `Rails::Engine` adds `app/controllers` path automatically to `autoload_paths`. Reference: rails/rails#12195 (comment) Closes activeadmin#697
In order to get files automatically reloaded in Rails, these files should be under `ActiveSupport::Dependencies.autoload_paths` directory. `Rails::Engine` adds `app/controllers` path automatically to `autoload_paths`. Reference: rails/rails#12195 (comment) Closes activeadmin#697
Does someone experiencing this issue could give activeadmin/activeadmin#2906 a try? I believe it should be fixed there. |
I haven't tried activeadmin/activeadmin#2906 in years, but even if it did "fix" the problem, there's still weirdness happening. The important thing to note with Active Admin is that the controller classes are dynamically defined at runtime, so they don't have a file to be reloaded from. Doing some tests, it appears that # Starting from a fresh IRB console, running Rails 4.2.5.1
require 'rails/all'
# ActionController holds onto the class
ActionController::Base.descendants.count => 0
class FooBar < ActionController::Base
end
ActionController::Base.descendants.count => 1
Object.send :remove_const, :FooBar
GC.start
GC.start
GC.start
ActionController::Base.descendants.count => 1
ActionController::Base.descendants => [FooBar]
FooBar -> uninitialized constant
# Even with Rails loaded, Object doesn't hold onto classes like that
Object.descendants.count => 1441
class FooBar < Object
end
Object.descendants.count => 1442
Object.send :remove_const, :FooBar
GC.start
GC.start
GC.start
Object.descendants.count => 1441
FooBar -> uninitialized constant |
What's odd about this is that the Mass gem isn't reporting any objects referring to the controller, that might prevent it from being garbage collected. Same with this setup: Mass.references ActionController::Base.descendants.first |
Even scoping the |
@seanlinsley yes, doing what you are doing is not supported :-(. Also please note that Furthermore PS: don't know if it will be of any help (it depends on what the rest of your app does, it might not be written in a way that is compatible with the gem) - with https://github.com/thedarkone/rails-dev-boost you should be able to do this: class FooBar < ActionController::Base
end
ActionController::Base.descendants.count => 1
Object.send :remove_const, :FooBar
ActionController::Base.descendants.count => 0 |
Ah, thanks for pointing that out. Object.method(:descendants).source_location
=> ["activesupport-4.2.5.1/lib/active_support/core_ext/class/subclasses.rb", 8]
ActionController::Base.method(:descendants).source_location
=> ["activesupport-4.2.5.1/lib/active_support/descendants_tracker.rb", 56] Can you elaborate on why exactly it isn't supported. I'm primarily here because I'm trying to better understand Rails autoloading. |
Simplicity of the implementation. On the other hand you have
If that is your goal, sure, but there is source code available for that 😈. |
It seems like this is still happening…? I had to keep restarting to test out authentication. But hopefully that won’t happen much… rails/rails#12195
before_action{raise}
to applicationcontroller, saveThe text was updated successfully, but these errors were encountered: