---
title: Why you should nest modules in Ruby
teaser: The differences between the two approaches to defining a class or module in
  Rails can seem like a small stylistic choice but learn the subtle gotchas with inline
  classes and modules when deciding which one to go with in your code.
tags: ruby
author: Justin Toniazzo
published_on: 2024-05-16
---

For the most part there’s no difference between these two ways of defining a class or module:

```ruby
# nested
module Admin
  class User
  end
end

# inline
class Admin::User
end
```

The difference is often described as stylistic, but there are a couple of functional differences between the two approaches that you should be aware of before choosing one over the other.

To illustrate, imagine an app with `User` and `Admin::User` classes. Depending on how you reference those, you’ll get two different results:

```ruby
module Admin
  class Nested
    def self.test = User.name
  end
end

class Admin::Inline
  def self.test = User.name
end

Admin::Nested.test # => "Admin::User"
Admin::Inline.test # => "User"
```

Here we use the [Module#name](https://ruby-doc.org/3.2.2/Module.html#method-i-name), which just returns the name of the class/module, e.g. `String.name` returns `"String"` .

You can see how when referencing `User` from within an inline class, the class that’s ultimately looked up is the top-level `User`, even though you’re in an `Admin` namespace so you likely intended to be referencing `Admin::User` instead.

You can get around that by using the fully qualified `::Admin::User` name:

```ruby
class Admin::InlineQualified
  def self.test = ::Admin::User.name
end

Admin::InlineQualified.test # => "Admin::User"

```

This also affects inheritance. For example consider these two `BaseController` classes:

```ruby
class BaseController
end

module Admin
  class BaseController
  end
end
```

As before, depending on how you reference them, you get two different results:

```ruby
module Admin
  class NestedController < BaseController
  end
end

class Admin::InlineController < BaseController
end

Admin::NestedController.superclass # => Admin::BaseController
Admin::InlineController.superclass # => BaseController
```

Confusing!

## Why does this happen?

The reason for this behavior has to do with how constants, like class and module names, are defined and referenced in ruby. You can see under the covers a bit by using the [Module.nesting](https://docs.ruby-lang.org/en/master/Module.html#method-c-nesting) method.

```ruby
module Admin
  class Nested
    def self.nesting = Module.nesting
  end
end

class Admin::Inline
  def self.nesting = Module.nesting
end

Admin::Nested.nesting # => [Admin::Nested, Admin]
Admin::Inline.nesting # => [Admin::Inline]
```

Here you can see that for the nested class, ruby is aware that the `Admin::Nested` constant is defined within an `Admin` namespace. Whereas with the inline class, ruby considers the `Admin::Inline` class to just be on its own.

It’s for this reason that, in the example above, the inline module returned `User` instead of `Admin::User`. When ruby is looking for where to find `User`, it will start by looking for that constant in the current namespace (e.g. looking for `Admin::Inline::User`), and then walk up the nesting tree until it encounters it. Since ruby does not consider the inline class to be nested under `Admin`, it doesn’t look for `User` in that namespace at all, and rather just goes straight to the top-level `User`.

## Creating the outer module

The other difference between inline and nested module definitions is how the outer module is created. If I were to define a module like this, without anything else:

```ruby
class One::Two
  # implementation
end
```

I’d get this error: `uninitialized constant One (NameError)` . This is because I’m attempting to reference the `One` constant before it’s defined.

This is why, especially in older apps, you’ll sometimes see empty module definitions like this:

```ruby
module Api
end
```

This is because there’s some class defined like this:

```ruby
class Api::UsersController
  # implementation
end
```

and since the `Api` module isn’t being defined there, it needs to be defined somewhere.

If instead it had been nested, it would work without the empty module:

```ruby
module Api
  class UsersController
  end
end

```

For this one I should note that, if you’re working with a recent version of Rails, the framework will handle creating that outer module for you if it doesn’t exist already. You can just define a `class Api::UsersController` without having first defined `module Api` anywhere else. So in that respect at least this is likely not the biggest issue for you. But still it’s good to be aware that this is non-standard ruby behavior in case you run into it when writing scripts or something :)

## Nesting is better

Because of these two differences, it’s better to just stick to nesting classes. You’ll pay a price in having to indent your code more, but you won’t have to worry about either of these gotchas, especially the first one. Rubocop even has [a rule for this](https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/ClassAndModuleChildren), making it super easy to add this to your CI pipeline.

If you’d rather use inline modules, it’s probably a good idea to stick to using the fully qualified name when referencing classes (e.g. `Admin::User` instead of `User`) to avoid any ambiguity.

## Want to learn more?

Learn about [the different services](https://thoughtbot.com/services/ruby-on-rails-development) thoughtbot offers and how we can work together in streamlining your projects.
