Rails namespace help requested


#1

Hi all -

I posted yesterday with the subject “namespace pollution” and with the
high traffic on this list, it’s kind of disappeared and I’m in need of
a quick answer so i can move on. To recap quickly, can someone tell
if Rails is somehow forcing all modules into a single namespace? I
have a model class StateProvince and inside a webservice module in my
lib/ directory I have a StateProvince as well but no matter what I do
when running under Rails I get a superclass mismatch error. This
doesn’t happen when I have standalone ruby code in similar situations.

Thanks for any help
Mike


#2

zdennis wrote:

Michael E. wrote:

class B; end
class B < A; end # error!!

This is the scenario you’re hitting with your namespace clash. Your
StateProvince class is being initalized, then when it gets around to
loading your StateProvince module it seems you’re trying to define
inheritance, and you can’t do that now.

I don’t mean to say it’s anything you’re doing on purpose. I think ruby
finds your StateProvince
class definition first, then it finds the StateProvince model
definition, which is where it tries to
subclass ActiveRecord::Base. At this point Ruby already has a definition
for StateProvince, and
although ruby lets us reopen the class we can’t subclass it because Ruby
defines the superclass of a
class when the class is first read in.

Zach


#3

Michael E. wrote:

By default Rails classes are using toplevel namespace; ie: ActiveRecord,
ActionController,
ActionView, etc…

Rails also does not put your models into a separate namespace (though i
wish it would =), and those
also are toplevel. ie: User, Account, Session, Group, Article.

If you have any classes that you wrote that have the same names as your
models or other toplevel
classes/modules that Rails is using you need to either a) rename them or
b) move them inside of
another namespace.

The problem you are having is that the first time you define/open a
class it has to define it’s
superclass.

class A ; end
class B < A; end

You cannot define/open a class and then later try to subclass it, ie:

class A; end
class B; end
class B < A; end # error!!

This is the scenario you’re hitting with your namespace clash. Your
StateProvince class is being
initalized, then when it gets around to loading your StateProvince
module it seems you’re trying to
define inheritance, and you can’t do that now.

If you have namespace clashes but you are in your namespace you can use
:: syntax to ensure you get
the toplevel class/module. For example:

class StateProvince
end

module MyNameSpace
class StateProvince
end

module MoreModules
   class MyStateProvinceModel < StateProvince
   end
end

end

In the above code code your MyStateProvinceModel is going to subclass
MyNameSpace::StateProvince
because that is the first constant ruby finds while it is looking for
“StateProvince”. This may be
wrong because your MyStateProvinceModel might need to subclass the
toplevel StateProvince class.
This is where the “::” comes in handy:

class StateProvince
end

module MyNameSpace
class StateProvince
end

module MoreModules
   class MyStateProvinceModel < ::StateProvince
   end
end

end

The leading :: on any constant will force ruby to look at the most
toplevel constant.

I hope this helps more then it confuses,

Zach


#4

Michael E. wrote:

class StateProvince
end
end

Isn’t the namespace declared for the class inside the module as
::WebServiceModule::StateProvince and the Rails model as
::StateProvince? Aren’t those different objects in the eyes or Ruby?

Yes.

Also I’m not doing inheritance in my WebServiceModule, I’m just
declaring a namespace right?

In your WebServiceModule you aren’t doing any explicit inheritance. From
your post from yesterday:

but when I run my code in Rails, I get a superclass mismatch error
when I include the module.

If you include you WebServiceModule in your top level, it will have a
problem when it finds the
StateProvince model. By saying:

include WebServiceModule

It will move WebServiceModule::StateProvince (and all other constants)
to scope that your “include”
statement is in. In this case it is in the toplevel/global scope and it
will be accessible as
::StateProvince.

So now that it is toplevel accessible and ruby finds your StateService
model which tries to subclass
ActiveRecord::Base you get your superclass problem!

I hope this helps!

I’m a bit new to Ruby so it’s possible I’m mixing this up but this is
what I understood from reading the pickaxe book.

ooh, good book. =)

Zach


#5

HI Zach -

THanks very much for your help. I’m not sure I understand why my
clash exists though because I have this exact scenario:

class StateProvince < ActiveRecord::Base
end

this is in a directory of lib/ws

module WebServiceModule
class StateProvince
end
end

Isn’t the namespace declared for the class inside the module as
::WebServiceModule::StateProvince and the Rails model as
::StateProvince? Aren’t those different objects in the eyes or Ruby?

Also I’m not doing inheritance in my WebServiceModule, I’m just
declaring a namespace right?

I’m a bit new to Ruby so it’s possible I’m mixing this up but this is
what I understood from reading the pickaxe book.

Thanks again for your help.

MIke


#6

AH!!! Thank you!!! I guess I needed to get whacked with a 2x4
regarding mixing in a module…The pickaxe booking didn’t explain it
as concisely. Thanks again

Mike