How can I extend my controller from installed Spree gem's controller?

596 Views Asked by At

I have spree gem installed successfully. I don't need spree_frontend. Here is the Gemfile

gem 'spree_core', '4.2.0.rc2'
gem 'spree_backend', '4.2.0.rc2'
gem 'spree_sample', '4.2.0.rc2'
gem 'spree_cmd', '4.2.0.rc2'
gem 'spree_auth_devise', '~> 4.2'

So I want to extend my ApplicationController from Spree's BaseController. Here is the code:

class ApplicationController < Spree::BaseController
  include Spree::Core::ControllerHelpers::Order
end

But I get following errors:

uninitialized constant Spree::BaseController (NameError)

How can I extend my controller from installed Spree gem's controller?

4

There are 4 best solutions below

1
inopinatus On BEST ANSWER

The problem you're running into is that Spree::BaseController already inherits from ApplicationController; see https://github.com/spree/spree/blob/master/core/app/controllers/spree/base_controller.rb. This is to allow your ApplicationController to define things like current_user and similar basic functions before Spree sees it.

Declaring them the other way around as well creates a circular dependency, and the class loading fails as a result. Without changing Spree itself, the only fix is to do something else.

Instead, to have your controllers use Spree::BaseController as a superclass, first define ApplicationController in the more usual fashion e.g.:

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  # ...
end

then invent a new abstract controller, for your own use, that inherits from Spree, e.g. let's name it StoreBaseController:

# app/controllers/store_base_controller.rb
class StoreBaseController < Spree::BaseController
  include Spree::Core::ControllerHelpers::Order
  # ...
end

This StoreBaseController can now be used in place of ApplicationController when defining more specific controllers. It works because it doesn't create a loop in the inheritance tree, which now looks like this:

Controller Hierarchy

Note: if you're also using the rails generator command to produce controllers or scaffolds from templates, be aware that the generator has ApplicationController hard-coded in the templates, so you'll need to amend them once created.

1
kykyi On

As the errors states, Spree::BaseController is not defined within your app - it is defined in the spree-core gem. If you re-create the filepath to the base controller locally, that is app/controllers/spree/, and copy and paste the code from the controller into a local base_controller.rb, you can edit it and add custom functionality.

Note that it will still inherit from the ApplicationController, but you can place any of the code you wanted to put in the ApplicationController into here and have your classes inherit from Spree::BaseContoller and the effect will be the same.

2
zhisme On

Is there any reason why you need to extend strictly ApplicationController?

I advise you alternative approach to create a new Base controller class, and then inherit all the children from it and leave ApplicationController to basic rails

app/controller/my_base_controller.rb

class MyBaseController < Spree::BaseController
  def foo
    # ...
  end
end

app/controller/my_resources_controller.rb

class MyResourcesController < MyBaseController
  def bar
    # ...
  end
end
0
kevinluo201 On

hmmm, I tried what you want to do but I succeeded (?)

class PagesController < Spree::BaseController
  include Spree::Core::ControllerHelpers::Order
end

in the console

2.6.5 :006 > pp PagesController.ancestors
[PagesController,
 Spree::Core::ControllerHelpers::Order,
 #<Module:0x00007fca27610410>,
 Spree::BaseController,
 Spree::Core::ControllerHelpers::CurrencyHelpers,
 Spree::Core::ControllerHelpers::StrongParameters,
...

I'm using

  • ruby 2.6.5
  • rails 6.0.3.4
  • run bundle update after adding the your spree's gems in the Gemfile

So I think its the requiring or auto-loading problem

  • what's your rails version? 6? spree >= 4.1 should use rails >= 6
  • Does Spree::BaseController exist in rails console?
  • Is Bundler.require(*Rails.groups) in config/application.rb?
  • Does the gems included in the right group of the Gemfile? ex: spree gems are in :production group.
  • Does it have config.load_defaults 6.0 in config/application.rb?