0

Ruby 2.1.7 and Rails 4.0.2

while working with rails console. I have seen that If I am declaring an Object in the console. Than calls reload! and then calls a method on that same object with code that create an instance of another class will raise an error:

ArgumentError: A copy of First has been removed from the module tree but is still active!

An example is much easier to understand:

In my app/model folders I declare to class:

app/models/first.rb

class First
  def foo
    Second.new
  end
end

app/models/second.rb

class Second
end

Than in the console I ran this commands:

x = First.new
reload!
x.foo

Than I get the exception

Can you give an explanation why is this happening? Is it mistake to use a reference that was declared before the reload? Is the exception is a good thing and I should not try to find a workaround or it shows that something in my code or configuration is wrong

I have this question: A copy of xxx has been removed from the module tree but is still active

One solution was to add extra :: as a prefix and indeed if I use this:

::Second.new

I do not get the exception

Do you think that using this solution is a good thing or is too much hacky and not the Ruby Way?

Can you explain why this does not cause the error?

Community
  • 1
  • 1
Natan Rubinstein
  • 665
  • 1
  • 9
  • 27

2 Answers2

1

Seems that it's not a good thing to reload the console environment and try to reference an instance created before it. So I don't think you should find a workaround for it.

1

This is due to the way Rails autoloads missing constant. In your example:
1. When "Second" is used, Rails firstly supposed it is a constant in "First" module, and to prevent using of an outdated module, it checks if the module with name "First" actually exists, and because "First" has not been autoloaded yet, it raises the exception.
=> which is a good thing (In your case, x should be an instance of an already defined class when being used)
2. When "::Second" is used, Rails supposed it is a constant in top-level, and just successfully resolves "Second" constant.
=> which I think is a bad thing
So, I agree with Sakata, you shouldn't find a workaround for it.

Manh Cuong
  • 101
  • 4
  • Thanks. I did not use any modules in my example only class so it is a little unclear to me what you mean. Also from your answer it seems that First keeps a reference to Second once it uses it. How does this magic happens? – Natan Rubinstein Feb 27 '17 at 08:18
  • **Thanks. I did not use any modules in my example only class so it is a little unclear to me what you mean.** Im sorry, what I mean in my explanation is "First" Class. By the way, Class's superclass is Module. – Manh Cuong Feb 27 '17 at 10:03
  • **Also from your answer it seems that First keeps a reference to Second once it uses it. How does this magic happens?** I dont know what you mean by saying "First keeps a reference to Second", I mean when you call x.foo, ruby execute the code and meet an unknown constant name "Second" and call "const_missing", this is where Rails comes in, overrides this method to autoload missing constant. You could reference "http://urbanautomaton.com/blog/2013/08/27/rails-autoloading-hell/" for more information about autoload in rails. – Manh Cuong Feb 27 '17 at 10:03
  • Thanks a lot I am starting to understand now. This complex and low level stuff of rails. I am hoping that the reference will help me understand more – Natan Rubinstein Feb 27 '17 at 10:31