NameSpaces and Modules in Rails
Overview
I’ve read a few different posts and articles on how to organize your Rails app codebase. Most eventaully reference modules
and namespaces as one good way to do it.
A lot of the basic examples show taking a module (or controller or view ) directory that looks like this:
And grouping the children (loose term) under the parent to bring connected code together (namespace or module).
Then you can update bar.rb from this:
to:
And this does work. Yay! (but don’t get too excited)
The above made me think that declaring a module
and a namespace are 100% the same thing. I could write either of the following and I’d get the exact same result.
is the same as:
##When $%^& Hit the Fan (ok it wasn’t that bad)
The thing that started to confuse me and made me question what I was doing is RuboCop was telling me to use nested definitions instead of the compact style. So I tried changing class Foo::Bar
to module Foo ...
and then I recieved an error saying Foo is not a module
when I loaded my webpage.
When I started re-reading the comments in the blog post and the accepted answer on StackOverflow I realized what was happening.
In this case class Foo::Bar
is looking for Foo
to be defined and it finds it as a class
so everything works. Once you try to break it out and declare Foo
as a module
it breaks because Foo
is a class
. So, if I wanted to keep the folder structure as is I could use the nested delcaration as follows:
And Bam, it works! But am I really wanting to nest my classes?
What we’re really doing here is nesting classes and using it as a namespace and calling it a module
. But it’s nesting classes to give reference to us (developers) as to how things are connected together. To me personally, I feel this is what modules
do a little better, at least in this case. Kind of like saying, “Hey, these classes aren’t nested I just think they belong together in various ways so lets give them a common name.”
I had been trying to figure out what the difference between namespaces and modules are in Rails (and by extension Ruby). I had started to think they are the same and interchangable. But now, I’m looking at it like this: NameSpaces are a way to reference related things demonstrating hierarchy. There are different ways to accomplish namespacing (i.e. nesting classes, nesting modules, nesting modules and classes). The NameSpace does not define the type of things being nested/grouped.
Another interesting piece with the above Foo::Bar
example is that Foo must already be defined when calling Foo::Bar
. When you call Foo::Bar
you are just looking it up. If Foo
hasn’t been previsouly defined, you’ll get an error. In the first case you’re defining module Foo
. The second is more of a reference. Also, you can’t define a class
and a module
with the same name.
Where I Landed
So for me, what I’m going to start trying is the following:
And grouping the children (loose term) under the parent to bring connected code together (namespace or module).
Then you can update bar.rb
from this:
to:
I’m doing this because I like the nested declaration of a module
. I also feel that in these cases I’m not wanting to nest a class
but group classes under a common area. To me a module
seems to be appropriate. Maybe I’ll change my mind in the future, but at least I’ve thought it through and am understanding what I’m doing a bit more vs. blindly jumping in.
References
- This answer in a SO question really helped things click
- Namespaced Classes in Rails - the comments were helpful too
- ORGANIZING LARGE RAILS PROJECTS WITH NAMESPACES was a great example but it helped enforce my original understanding of namespacing and modules
- How DHH Organizes His Rails Controllers
- Using “::” instead of “module …” for Ruby namespacing
- Ruby - Lexical scope vs Inheritance