`circular dependency` - inheritance in application controller of Rails 4.2.0 engine - ruby-on-rails

When upgrading engine from Rails 3.2 to Rails 4.2.0, the following inheritance in application controller causes circular dependency error in rspec:
class ApplicationController < ApplicationController
end
We have config.eager_load = false for config/development.rb.
The error:
activesupport-4.2.0/lib/active_support/dependencies.rb:492:in `load_missing_constant': Circular dependency detected while autoloading con
stant Authentify::ApplicationController (RuntimeError)
Here is the Rails engine document (ch:4.3.2) explaining this type of code practice. As I understand, the purpose of this inheritance is to allow the engine to access methods in Rails app or other engine which the current engine is mounted to. We would like to do the same in Rails 4.2.0 engine. How to fix this problem?

your applicationController is clearly trying to inherit from itself, it should rather look like
class ApplicationController < ActionController::Base

In rails 4 engine, the right format is:
class ApplicationController < ::ApplicationController
end
assume the class is within module MyEngine. Or
class MyEngineName::ApplicationController < ::ApplicationController
end

Related

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

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?
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:
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.
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
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.
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?

Understanding the basic inheritance in Ruby on Rails

I am new to Ruby on Rails Development and was trying to understand inheritance in Rails, I understood how do a class inherit from a parent class
For Example MyController < ActionController, in this Action Controller is the parent class. But I dont understand this syntax
ApplicationController < ActionController::Base
Specifically what is the purpose of ::Base
This syntax is used to indicate that Base is a class inside of ActionController namespace.

Active admin error on Rails 4.0.2 application

Got this error while installing active admin on rails 4.0.2 application. I am using rails-api, where I need something like this admin to manage content apart from client.
undefined method `layout' for ActiveAdmin::Devise::SessionsController:Class
I am not sure about this error.
Okay looks like it has been solved by adding this on application controller.
include AbstractController::Layouts
It is now ActionView::Layouts
See https://github.com/rails/rails/issues/14517
When use rails-api(it's merged into rails 5 now), your ApplicationController will inherits from ActionController::API instead of ActionController::Base, while rails admin dependents on ActionController::Base and some other middlewares. To make active admin works with rails api mode, your need to do some additional work:
Make your ApplicationController inherit from ActionController::Base
class ApplicationController < ActionController::Base
Modify your config/application.rb like this
class Application < Rails::Application
# ...
config.middleware.use ActionDispatch::Flash
config.middleware.use Rack::MethodOverride
config.middleware.use ActionDispatch::Cookies
end
References:
1. https://rrott.com/blog/ror/rails-5-api-with-activeadmin-integration.html
2. What is the difference between a regular Rails app and a Rails API?

Create bare rails controller class

I'm trying to create clean controller based on ActionController::Base. That's what I try:
class MetalController
ActionController::Base.without_modules(:ParamsWrapper, :Streaming).each do |left|
include left
end
end
From Rails doc:
Shortcut helper that returns all the modules included in
ActionController::Base except the ones passed as arguments:
This gives better control over what you want to exclude and makes it
easier to create a bare controller class, instead of listing the modules
required manually.
My another controller inherits from MetalController :
class API::BaseController < MetalController
#.... my awesome api code
end
So this not work then i launch rails server:
block in <module:AssetPaths>': undefined methodconfig_accessor' for
MetalController:Class (NoMethodError)
Rails 4.1.0, Ruby 2.1.0
Update:
If i include ActiveSupport::Configurable
throws the errors:
_implied_layout_name': undefined local variable or method
controller_path' for MetalController:Class (NameError)
You need to inherit from ActionController::Metal:
class MetalController < ActionController::Metal
ActionController::Base.without_modules(:ParamsWrapper, :Streaming).each do |left|
include left
end
end

Rails 3 engine application controller

I have a rails engine that expose the following controller:
class ActsAsAssets::AssetsController < ApplicationController
..........
The main application uses devise into the ApplicationController. From the main application I use to extend the Engine Controller normally like this:
class MainApplicationController < ActsAsAssets::AssetsController
.......
What I was aspecting is that MainApplicationController was extending the main application ApplicationController via the engine.
Note that the engine does not have any ApplicationController so I was expecting ActsAsAssets::AssetsController < ApplicationController to actually extend the ApplicationController of the rails app that uses the engine.
Looks like I am wrong.
Any suggestion?
Basically what I want to achieve is that a controller from my main app extends a rails engine controller that extends the main ApplicationController cause does not have one inside the engine.
Hoper is clear.
Change the declaration to look like this:
class ActsAsAssets::AssetsController < ::ApplicationController
That instructs the controller to extend the non-namespaced ApplicationController from the main application.

Resources