5
votes

I have a weird issue when creating a controller spec for a namespaced controller when there also is a global controller with the same name.

The controller names are HomeController and Backend::HomeController.

Note that I have not yet created the file app/controllers/backend/home_controller.rb, only the global controller exists app/controllers/home_controller.rb

Therefore I expect the test to explode with errors, but it does not. It passes, all green and happy.

My spec looks like this

#spec/controllers/backend/home_controller_spec.rb
require 'rails_helper'

RSpec.describe Backend::HomeController, type: :controller do
  before do
    user = FactoryGirl.create(:user)
    allow(controller).to receive(:authenticate_user!).and_return(true)
    allow(controller).to receive(:current_user).and_return(user)
  end
  describe "GET #index" do
    it "returns http success" do
      get :index
      expect(response).to have_http_status(:success)
    end
  end

end

However if I change the name in my global HomeController to something else, e.g NotMyHomeController the test fails with errors saying

Unable to autoload constant HomeController, expected app/controllers/home_controller.rb to define it

Which makes me suspect that Rspec doesn't bother with the "Backend" part in the Rspec.describe function.

Am I doing something wrong or am I missing some other vital part? IMHO, this spec shouldn't pass (to paraphrase Gandalf).

I'm using Rails 4.2.6, Rspec-Rails 3.4.2

Update

As Max pointed out, this is probably not at Rspec issue but instead something with Rails autoloading.

However i tried just typing

Backend::HomeController

In the Rails console, but there I get the expected error

NameError: uninitialized constant Backend::HomeController

And according to the Rails guide, both the console and the test suite autoloads. However I think I'm on the right track here.

1
I'm guessing that its the Rails autoloader doing something screwy - it works by monkeypatching Object.const_missing which would have normally just raised NameError: uninitialized constant Backend::HomeController. It has very little to with RSpec.max
Thank you for clearing that up for me. Do you have any suggestions on how to investigate the Rails Autoloader further?Jacob Rastad
You might want to try and see what happens if you define it as absolute rather than relative: RSpec.describe ::Backend::HomeControllermax
Thank you for the tip, unfortunately using the absolute name didn't help, still the same problem and error message if I change the name of the global HomeControllerJacob Rastad

1 Answers

3
votes

I had this same problem before - you can read about the whole issue here:

Object.const_get and Rails - cutting off parent module names

but the meat of the answer comes from this answer from user Apneadiving:

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.