Ruby namespacing
When you use
#The code in question
module Api
module V1
class UserController < ApplicationController
end
end
end
ApplicationController
definition will be searched in Api::V1
then if not found in Api
then if not found in the root namespace.
I agree it could be confusing, that's why I tend to use absolute paths like so: ::ApplicationController
If ever I'd need Api::ApplicationController
, I'd write ::Api::ApplicationController
Basically the ::
tells ruby to start from the root namespace and not from where the code lives.
Sidenote
Be aware that there are vicious cases in Rails development mode. In order to gain speed, the strict minimum is loaded. Then Rails looks for classes definitions when needed.
But this sometimes fails big time example, when you have say ::User
already loaded, and then look for ::Admin::User
. Rails would not look for it, it will think ::User
does the trick.
This can be solved using require_dependency
statements in your code. Speed has a cost :)
Understanding namespaces in Ruby
ZipkinTracer
is inside of Trace
namespace, like this:
module Trace
class ZipkinTracer
# ...
end
end
The ::
before constant name means that you point to the root. For example in the following code:
class Class1
end
module Module1
class Class1
end
def foo
::Class1
end
end
::Class1
ensures that you refer to the "root" Class1
. If you had:
def foo
Class1
end
the Module1::Class1
would be referred.
What's the difference between these Ruby namespace conventions?
The difference lies in nesting.
In the example below, you can see that the former method using class Foo, can get the outer scope's constant variables BAR_A without errors.
Meanwhile, class Baz will bomb with an error of uninitialized constant A::B::Baz::BAR_A. As it doesn't bring in A::* implicitly, only A::B::*explicitly.
module A
BAR_A = 'Bar A!'
module B
BAR_B = 'Bar B!'
class Foo
p BAR_A
p BAR_B
end
end
end
class A::B::Baz
p BAR_A
p BAR_B
end
Both behaviors have their place. There's no real consensus in the community in my opinion as to which is the One True Ruby Way (tm). I personally use the former, most of the time.
Ruby namespacing with a class vs. module?
The most immediate benefit to using modules for namespacing is that you can use include
to import the namespace, and use the constants declared within it unqualified:
module Foo; class Bar; end; end
module Elsewhere
include Foo
Bar.new
end
Ruby Class namespacing with modules: Why do I get NameError with double colons but not module blocks?
It may seem counter-intuitive, but constant lookup in Ruby is done using current lexical scope, i.e. the current lexical nesting level (location in the source code), not the semantic nesting level.
This can be tested by inspecting Module.nesting
, which prints the current lexical scope:
class Foo::SecondClass
pp Module.nesting # -> [Foo::SecondClass]
end
module Foo
class SecondClass
pp Module.nesting # -> [Foo::SecondClass, Foo]
end
end
Since Ruby uses this nesting level for symbol lookup, it means in the situation where you try to look up FirstClass
within nesting [Foo::SecondClass]
, Ruby will not find it.
However when you try to look it up within nesting [Foo::SecondClass, Foo]
, it will find FirstClass
under Foo
, just like you expect.
To get around this, you could do:
class Foo::SecondClass
def meth
Foo::FirstClass.new.meth
end
end
Which will now work as you expect, since you provided the necessary lookup hint for FirstClass
, and told Ruby it is inside Foo
.
What is a Namespace?
A namespace provides a container to hold things like functions, classes and constants as a way to group them together logically and to help avoid conflicts with functions and classes with the same name that have been written by someone else.
In Ruby this is achieved using modules.
Rails, Ruby classes / modules / namespaces confusion
You may need an intermediate A::B declared in a/b.rb
to properly define the module A::B
before you reference it, or you can re-style your declaration in your final file.
For example:
# a/b/c.rb
class A::B::C
end
This depends on module or class A and A::B being defined before that file is loaded.
You can side-step this:
class A
module B
class C
end
end
end
That will force-declare all the intermediates. As this introduces a lot of indentation, a slightly less messy approach is:
class A
module B
end
end
class A::B::C
end
Of course, having an a.rb
and a/b.rb
with the appropriate intermediate declarations often helps avoid all of this.
Namespacing in Ruby require
You will want to wrap your code in an actual module
or class
something like
class Foo
def self.bar
"quxx"
end
end
This way, you will be able to call Foo.bar
to access your method.
Proper rails model namespacing
Indeed, if you do that, Ruby will complain because Party
can't be a module and a class at the same time. So at least, Party
would need to remain a class.
Now as the "Rails way" is concerned, we don't usually subclass our associations (ie. your Chat
will probably belong_to
a Party
), we just put all our models in the root namespace (unless one has a good reason to). So you'd have Party
at app/models/party.rb
and Chat
at app/models/chat.rb
.
I'm guessing one would make a namespaced subclass Party::Chat
only if there's a different ::Chat
already present, and even that could lead to trouble with Ruby's constant lookup which is sometimes counter-intuitive.
Related Topics
How to Decode Q-Encoded Strings in Ruby
Can't Run Bundle Update on Windows
How to Render File in Rails 5 API
Accepts_Nested_Attributes_For Ignore Blank Values
Optional Parens in Ruby for Method with Uppercase Start Letter
How to Use Same Browser Window for Automated Test Using Selenium-Webdriver (Ruby)
Rails Shows "Warning: Can't Verify Csrf Token Authenticity" from a Restkit Post
Undefined Local Variable Based on Syntax in Ruby
Error in Celluloid Gem Installation
Save All Image Files from a Website
Rails Fastercsv "Unquoted Fields Do Not Allow \R or \N"
What Is the Standalone Splat Operator (*) Used for in Ruby
How to Upload a File with Watir and Ie
Adding a Background Image in Ruby on Rails 2 in CSS
What Does +@ Mean as a Method in Ruby