It is beyond anything you have ever experienced or imagined
Can’t dup NilClass… maybe try `unloadable`
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 < ActiveRecord::Base include Authentication::ByCookieToken include Authentication::AccountBuddy has_many :logins, :dependent => :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 # <= That's the ticket! include Authentication::ByCookieToken include Authentication::AccountBuddy # reverse-micro-plugin has_many :logins, :dependent => :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.
| Print article | This entry was posted by Daniel X Moore on April 23, 2009 at 8:02 pm, and is filed under Programming. Follow any responses to this post through RSS 2.0. You can leave a response or trackback from your own site. |
about 1 year ago
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).
about 1 year ago
Thank you so much!
about 1 year ago
@Polydectes, @Tobias : You’re welcome, I’m glad I could help!
about 1 year ago
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!
about 1 year ago
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’
about 1 year ago
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?
about 1 year ago
@paul Thanks for the alternative solutions. I’ll be sure to check them out for my next plugin.
@Mans Happy to have helped!
about 1 year ago
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!
about 1 year ago
Thank’s man! That’s really helped out. Just awesome )
about 1 year ago
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.
about 1 year ago
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
about 1 year ago
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
about 1 year ago
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
about 12 months ago
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!!!!
about 11 months ago
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’.
about 11 months ago
@Gary: No, I still get a can’t dup NilClass error wit rails 2.3.4
about 11 months ago
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’
about 11 months ago
@Kris :
which init.rb please? Thanks
about 11 months ago
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’
about 10 months ago
Thanks, thanks, thanks!
Writing code is a pleasure again
about 9 months ago
thank you so much!
@Gary: I’m using 2.3.4 and I had the same problem.
about 9 months ago
@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).
about 8 months ago
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.
about 8 months ago
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
about 5 months ago
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
about 5 months ago
@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…
about 5 months ago
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.
about 3 months ago
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
about 1 month ago
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