Why you Should not use a Class as a Namespace in Rails Applications

Posted on by Artem Sarkisov

This is a guest post by Junichi Ito (@jnchito). Junichi is a Ruby programmer at SonicGarden.jp, translator of Everyday Rails Testing with RSpec, and one of the most popular Ruby writers/bloggers in Japan


If you use a class as a namespace, it can produce a bug that doesn’t always show up on the surface. You should different names for your model class and your namespace in Rails applications.

class Staff < ApplicationRecord

# Shoud not use class as namespace
class Staff::ItemsController < ApplicationController

# Should use a different name for namespace
class Staffs::ItemsController < ApplicationController

Hidden bug with a class name as a namespace

You can use both classes and modules as a namespace. But if you use a class, it might lead to unexpected behavior, especially in Rails applications.
For example, you have two classes called Item and Staff:

class Item < ApplicationRecord
  scope :published, -> { where(published: true) }

class Staff < ApplicationRecord

You want to create two pages, one is for end users and the other is for staffs. End users can see published items only, but staffs can see all items. Then, you create these two controllers:
class ItemsController < ApplicationController
  def index
    @items = Item.published

class Staff::ItemsController < ApplicationController
  def index
    @items = Item.all

But Staff::ItemsController sometimes works wrong. It might return only published items. Why? This problem is related to Ruby’s constant lookup rule.

For an explanation, I’ll use a simpler example. If you run the code below in irb, you can refer to Staff::ItemsController without definition:

class Item; end
class Staff; end
class ItemsController; end
# Refer to Staff::ItemsController without definition
# warning: toplevel constant ItemsController referenced by Staff::ItemsController
#=> ItemsController

You can see that Staff::ItemsController returns ItemsController. Here’s why:

  • Top level constants always belong to an Object class, so ItemsController is equal to Object::ItemsController.
  • When Staff::ItemsController is referred to, Ruby cannot find the constant ItemsController in the Staff class. Then, Ruby tries to find it from the Staff class’s ancestors.
  • You can confirm ancestor classes and modules with Staff.ancestors. It returns [Staff, Object, Kernel, BasicObject] in the sample code above.
  • Ruby tries to find ItemsController in the Object class which is next to the Staff class in the ancestors array. Does the Object class have ItemsController? Yes, Ruby could find ItemsController successfully, because Object::ItemsController is already defined.
  • But it might be a wrong lookup, so Ruby gives the warning “toplevel constant ItemsController referenced by Staff::ItemsController.” In fact, this case does not match our intention.

However, when Staff::ItemsController is already defined, Staff::ItemsController can be referred to not by ItemsController, but by Staff::ItemsController because Ruby can find ItemsController in the Staff class:

class Item; end
class Staff; end
class ItemsController; end
class Staff::ItemsController; end

# Refer Staff::ItemsController after definition
#=> Staff::ItemsController

When the application is run, sometimes Staff::ItemsController can be referred to after definition and sometimes referred to before definition. The former leads to expected behavior and the latter leads to unexpected behavior. This is the hidden bug.

This problem can also occur in Rails applications. When you run Staff.ancestors in the rails console, you can see a lot of classes and modules. But the Object class does exist in ancestors. So this means that Staff::ItemsController can refer to Object::ItemsController when Staff::ItemsController is not defined.

Use different names for your model class and your namespace

To avoid this problem, you should use different names for your model class and your namespace, for example, Staffs::ItemsController.

If Staffs::ItemsController is defined in the app/controllers/staffs directory and the constant Staffs is not defined yet, Rails defines the Staffs module automatically. (This function is called “Automatic Modules”. Please see Rails Guides for details.)

When the namespace is a module, the constant lookup leads to different results from the class namespace, because the module does not have ancestors other than itself. Let us see the results in irb:

class Item; end
class Staff; end
class ItemsController; end
module Staffs; end

# Confirm Staffs module's ancestors
#=> [Staffs]

# Refer to Staff::ItemsController without definition
#=> NameError: uninitialized constant Staffs::ItemsController
#   Did you mean? ItemsController
#       from (irb):6
#       from /Users/jit/.rbenv/versions/2.4.0/bin/irb:11:in `<main>'

This time, Staffs::ItemsController was considered to be an uninitialized constant. This is because the Staffsmodule does not have Object in its ancestors. So Ruby won’t look up Object::ItemsController and the constant lookup fails.

Rails can load Staffs::ItemsController without errors

In irb Staffs::ItemsController is an uninitialized constant and Ruby produces an error, but this scenario is different in Rails applications. Rails implements the const_missing hook and tries to find Staffs::ItemsController in autoload_paths. If Staffs::ItemsController is defined in autoload_paths like app/controllers/staffs/, Rails can load Staffs::ItemsController without any errors. Please see Autoloading and Reloading Constants in Rails Guides for details.

NOTE: The problem described in this post might be fixed in the future

The top-level constant lookup rule in Ruby might be changed in a future version, because the topic “remove top-level constant lookup” is being discussed here:


Please check it out if you are interested.

By Junichi Ito.

Have a Ruby/Rails case to share with the community? Let us know in the comments below!

Your RubyMine Team

Comments below can no longer be edited.

3 Responses to Why you Should not use a Class as a Namespace in Rails Applications

  1. PikachuEXE says:

    March 31, 2017

    Yup to avoid this I have tried this too:

    module Staffs
      class ItemsController

    But in the end I try to do DDD instead:

    # Apps::MyWebsite is just a namespace 
    # that should never be used by gems
    # You can use whatever that works
    # StaffItemListPage is how you name the page type (not route) internally
    # Naming it is sometimes quite hard 
    # Also the URL does NOT represent the page type
    # It can be moved to another URL later
    # I also define one controller class per action like Hanami
    module Apps::MyWebsite::StaffItemListPage::Show
      class ActionController
  2. Ruby Inspector says:

    March 8, 2018

    With the release of Ruby 2.5 this has been fixed. So go now and use classes as namespaces as much as you want. Yay!

    • Vasyl says:

      August 26, 2019

      Thanks for the information. Could you please give some link to the source and details about this fix?


Subscribe for updates