If you’re using a model or controller from an engine in Rails 2.3.2 you may encounter some crazy errors from time to time. Errors like: A copy of ApplicationController has been removed from the module tree but is still active!
Or sometimes the even weirder one: can't dup NilClass
In one situation where you get A copy of ApplicationController has been removed from the module tree but is still active!
it could be because you’re using a plugin or engine that provides controllers and inherits from ApplicationController. Some of the classes inherited or included in your engine controllers may fail to get unloaded and cause trouble after the first request to your system. Add unloadable
inside your controller classes in your engine.
The can't dup NilClass
error really tricked me though. It seemed to be saying something about duping nil class but not really. It was a lie! Well, almost. See, I had a model in my engine like this:
class Account :destroy attr_accessible :nickname, :email
And I had a module in my app (not in the engine) like this (sort of a reverse-micro-plugin):
module Authentication module AccountBuddy def self.included(account) account.class_eval do has_many :characters end end end end
And when I tried to access account.characters
it was all “can’t dup NilClass”. But what it really meant to say was: “I’m returning nil instead of an array containing the characters belonging to this account because I became confused during the loading and unloading of all your crazy ass models. -Love, Rails”
So adding a little unloadable
also fixes that.
class Account < ActiveRecord::Base unloadable # :destroy attr_accessible :nickname, :email
What a load off.
A better way
Courtesy of Paul (from the comments)
unloadable
is now deprecated, I think. As far as I am aware, the “right” way to do this is one of the following:
First, you could put something like this in your plugin’s init.rb file:
# This plugin should be reloaded in development mode. if RAILS_ENV == 'development' ActiveSupport::Dependencies.load_once_paths.reject!{|x| x =~ /^#{Regexp.escape(File.dirname(__FILE__))}/} end
Second, you could put something like this in your application’s environment.rb file:
config.reload_plugins = true if RAILS_ENV == ‘development’
If the above did not solve your problem:
Courtesy of Evan Owen (from the comments)
Another possible cause of this problem is that ActiveRecord
also defines self.included
. In order to ensure that ActiveRecord
gets the call and can finish loading the model, a call to super
needs to be added to the end of self.included
like so:
def self.included(account) account.class_eval do has_many :characters end super # fixes the "can’t dup nil" issue end
This did not work in my specific case, but may be the correct solution if you are suffering from a similar but different problem.
Thank you for this entry. I’ve been fighting these issues all over the place for about 4 weeks and yours is the first place I’ve found a solution to both issues I’ve been having.
Strange: The “{}Controller has been removed” issue is by design (and has been known and not well documented since 2006 (I found the solution in trac about 3 hours before I found this post).
LikeLike
Thank you so much!
LikeLike
@Polydectes, @Tobias : You’re welcome, I’m glad I could help!
LikeLike
htf did you figure this out? haha.
you just saved my day. i have an app that is built up of all kinds of desert_plugins and shortly after updating to 2.3.2 i started getting that weird “Can’t dup NilClass error.”
my conflict was in a model though. the first time my page would load (after a server start) everything worked fine. the second time the page loaded, i got the NilClass error.
adding ‘unloadable’ to the model in my desert plugin solved it all.
thanks for the tip!
LikeLike
unloadable is now deprecated I think. As far as I am aware, the “right” way to do this is one of the following.
First, you could put something like this in your plugin’s init.rb file:
# This plugin should be reloaded in development mode.
if RAILS_ENV == ‘development’
ActiveSupport::Dependencies.load_once_paths.reject!{|x| x =~ /^#{Regexp.escape(File.dirname(__FILE__))}/}
end
Second, you could put something like this in your application’s environment.rb file:
config.reload_plugins = true if RAILS_ENV == ‘development’
LikeLike
Thank you! Thank you! Thank you!
I’ve been beating my head against this obscure error for days, doing work on an engine in rails 2.3.2.
Cut. Paste. Solved.
Now, where was I?
LikeLike
@paul Thanks for the alternative solutions. I’ll be sure to check them out for my next plugin.
@Mans Happy to have helped!
LikeLike
I used Paul’s solution because it evidently affects development environment only. That plus his statement that unloadable might be deprecated.. But anyway thanks to both of you daniel and paul!
LikeLike
Thank’s man! That’s really helped out. Just awesome )
LikeLike
Thanks man, this post helped me out. I ended up putting:
load_paths.each do |path|
ActiveSupport::Dependencies.load_once_paths.delete(path)
end if config.environment == ‘development’
in my engine’s init.rb file. All good.
LikeLike
I’m still trying to figure out a problem that produces the same error message. I’m not completely up to speed on unloadable. We’re not using any plugins or engines here, I’ve reproduced the problem in a sample rails app. The problem happens with Paperclip and multiple file uploads from a flash uploader. The first one works great, but the second POST request produces the error. If anyone could take a look at this that would be great. It is a simple example of file uploads with JS+Flash, currently only working for one upload.
http://github.com/webandy/uploadifytest/tree/master
LikeLike
I was getting this exact same error, in development mode only. It turned out the problem was in a file in my “lib” directory, which was calling “require” for a couple of models. This *somehow* caused the models to not be loaded properly on subsequent requests (thus it would work the first time), causing the “Can’t dup NilClass” error that has driving me absolutely insane for almost 48 hours.
There a little bit more background on the *why*, plus other, similar scenarios in which this could happen on these two threads:
http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/f54f18f4d4354926?pli=1
http://groups.google.com/group/rubyonrails-core/browse_thread/thread/0675477c3fb23bf2/787b561d166abf53?#787b561d166abf53
LikeLike
I haven’t tried yet, but I think Rails 2.3.4 fixes the problem entirely.
http://weblog.rubyonrails.org/2009/9/4/ruby-on-rails-2-3-4
LikeLike
This explains the error that suddenly started in my app. I had added a call to self.dosomething from a scheduled task created by Rufus.Scheduler. This must have loaded my model into the engine or some weird thing, locking up regular ‘interactive’ access to the model.
Thank you!!!!
LikeLike
I’m having a Can’t dup NilClass, but unloadable didn’t do the trick, pitty. Anyway, just a little typo in your post: in the example, you wrote ‘unloabable’. 🙂
LikeLike
@Gary: No, I still get a can’t dup NilClass error wit rails 2.3.4
LikeLike
It doesn’t seem to be fixed in 2.3.4 and unloadable is deprecated, but thanks to this post I found the solution to add the below to init.rb.
load_paths.each do |path|
ActiveSupport::Dependencies.load_once_paths.delete(path)
end if config.environment == ‘development’
LikeLike
@Kris :
which init.rb please? Thanks
LikeLike
Thanks so much! I was getting can’t dup NilClass when adding a has_many :through on a model that is defined inside an engine. Adding this to my environment.rb solved the problem!
config.reload_plugins = true if RAILS_ENV == ‘development’
LikeLike
Thanks, thanks, thanks!
Writing code is a pleasure again 🙂
LikeLike
thank you so much!
@Gary: I’m using 2.3.4 and I had the same problem.
LikeLike
@Brad: Ta, my messages were also caused by an unnecessary “require ‘user'” in a file in the lib folder. After removing the “require ‘user'” the problem went away. Another problem that went away when I did this was before_update being called twice in test mode (http://dev.rubyonrails.org/ticket/480).
LikeLike
Snap this started happening today after I updated my XUbuntu system to the latest. I guess the process fudged my rails files. I am not using engines. Maybe it is because I have a model named User? What gives? I don’t want to go around putting some crazy ass line like unloadable in all my models. That is just stupid in my opinion.
LikeLike
I still get the problem, and I don’t know how to fix it. The solutions listed above cannot fix it. The only option I can choose now is to downgrade to rails 2.2.2
LikeLike
Actually, the real cause of this problem is that ActiveRecord also defines self.included, and since you’re not calling “super” inside your method, ActiveRecord never gets the call and can’t finish loading your model, causing the “can’t dup nil” errors when you try to call the association.
To fix this, simply do:
def self.included(account)
account.class_eval do
has_many :characters
end
super # fixes the “can’t dup nil” issue
end
LikeLike
Thanks Evan! That’s a better explanation and makes a lot of sense. I’ll try it that way the next time I encounter the issue.
LikeLike
@Fred – in my case the init.rb in my plugin as that is where I was getting the error. It maybe different if you are getting the error for your Rails app itself…
LikeLike
Just wanted to add yet another method of addressing this issue (when all the others don’t seem to work for you). Credit goes to James Adam for pointing me in the right direction and the comments in this article.
See http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/f54f18f4d4354926?pli=1 for an explanation.
In environment.rb:
Rails::Initializer.run do |config|
# etc
config.to_prepare do
# use load to ensure the added functionality is actually evaluated every time
load 'path/to/your/extension.rb'
end
end
LikeLike
I used Kris fix in the plugin init.rb and it fixed the problem and the “A copy of ApplicationController has been removed from the module tree but is still active!” has gone.
Thanks Kris & Daniel
LikeLike
I just ran into the ‘A copy of ApplicationController has been removed from the module tree but is still active!’ problem using Rails 2.3.8 and BrowserCMS 3.1.2.
As soon as I was calling ApplicationController’s methods from my custom controllers, the exception would occur.
Paul’s solution works nicely for me.
LikeLike
The “Can’t dup NilClass” error can also happen with Time.parse when you pass in a nil value:
oh_noes = nil
Time.parse(oh_noes)
I assume the parse method dupes the value to make sure it doesn’t modify yours, hence the error.
This is what caused ours. 🙂 Likewise I assume any method that tries to dup without checking for nil first will throw this.
LikeLike
Solution similar to Nathan Hyde’s above:
Rails 2.3.5
Problem: Dev mode wants to reload before every request. Rails initialization gets messed up when reloading code from plugins and monkeypatches. The plugin or patch isn’t loaded at all or, if it is, things that you expect to be defined at reload time aren’t.
My case: monkeypatching the Tag model in acts_as_taggable_on_steroids to add a has_many association
Solution: Wrap the monkeypatch code in:
require ‘dispatcher’
Dispatcher.to_prepare do
Tag.class_eval do
# patches
end
end
Resources:
http://stackoverflow.com/questions/2397740/how-to-extend-an-unloadable-rails-plugin
http://www.oliyiptong.com/blog/2008/08/22/rails-to_prepare-executing-code-before-each-request/
Just another option in case you don’t want to edit environment.rb.
LikeLike
The comment by Evan saved my day!
I had the same error when using self.inherited. ActiveRecord::Base also defines this method, not only included – calling super solved the problem with “can’t dup NilClass”. Great post, thanks.
LikeLike
Wao! thanks a lot for this post… you save my day.. I was suffering with this problem
LikeLike