So I wrote a little portfolio app in Rails 4. It has an admin namespace to allow me to only expose certain controllers to public.
Everything works great when in development, but when I deploy to a production env (or switch to production on my dev machine) I get the following error:
superclass mismatch for class WorksController (TypeError)
My controller structure looks like this:
controllers ->
admin ->
admin_controller.rb
portfolio ->
works_controller.rb
portfolio->
works_controller.rb
As you can see, I namespaced works inside of portfolio.
The controllers are declared as following:
/controllers/admin/admin_controller
class Admin::AdminController < ApplicationController
/controllers/admin/portfolio/works_controller
class Admin::Portfolio::WorksController < Admin::AdminController
/controllers/portfolio/works_controller.rb
class Portfolio::WorksController < ApplicationController
Now for my routes.rb, note I am using Friendly ID so I used a custom route to have a pretty client facing url.
get '/portfolio/:id' => 'portfolio/works#show', as: 'portfolio_work'
namespace :admin do
namespace :portfolio do
resources :works
end
end
So I know I must have screwed this up somehow, but I don't know how. The error I get is related to redeclaring a class, but I don't know how I managed to do so.
Any help is greatly appreciated.
Found this fix after #ReggieB tried to help me. Turns out having my Devise model 'Admin' and a namespace also called 'Admin' creates problems (as it should).
What happens if you redefine /controllers/admin/portfolio/works_controller line this:
module Admin
class Portfolio::WorksController < AdminController
Related
I have rails 4.1.16 API application that is tested using RSpec 3.4.0, and I experience problems with testing classes called the same name in a different module.
The structure is:
app/controllers/bar/notifications_controller.rb
class Bar::NotificationsController < ApiController
...
end
and controller with the same name in a different module:
app/controllers/foo/bar/notifications_controller.rb
module Foo
class Bar::NotificationsController < ApiController
...
end
end
The Foo is a new module and does not have tests yet.
After adding it, all the corresponding controller tests for the old Bar::NotificationsController started to fail.
The spec file:
spec/controllers/bar/notifications_controller_spec.rb
require 'spec_helper'
describe Bar::NotificationsController, type: :controller do
...
end
All the tests in that spec file fail with the same error:
RuntimeError:
#controller is nil: make sure you set it in your test's setup method.
The problem does not exist when I change the controller name in the Foo module:
app/controllers/foo/bar/foo_notifications_controller.rb
module Foo
class Bar::FooNotificationsController < ApiController
...
end
end
I already tried adding on top of the spec file require 'bar/notifications_controller' and using the class name as a string describe "Bar::NotificationsController, type: :controller but it did not solve the issue (the same error).
Why is this happening? What is the solution?
I want to believe there is a tiny thing I did not try yet and I don't have to pollute my code and the structure with nonsense names just to make the specs pass.
Many thanks in advance for your help!
In general, I've take to including all namespacing in the class definition. Something like:
app/controllers/foo/bar/notifications_controller.rb
class Foo::Bar::NotificationsController < ApiController
...
end
While, at first glance, this might look the same as:
app/controllers/foo/bar/notifications_controller.rb
module Foo
class Bar::NotificationsController < ApiController
...
end
end
These are, in fact, different. The difference is in how Rails handles autoloading of constants. I won't go into the details here because it's a longer topic and there are good articles/posts out in the web-o-sphere.
You can find good articles on how Rails handles autoloading like this one (or try Googling rails constant loading)
Also, as the article notes, Ruby constant loading operates differently than Rails loading. Good information on Ruby constant loading can be found here (or try Googling ruby constant loading).
How can I tell Rails (5 beta3) to look for namespaced models in app/models instead of in app/models/namespace?
I have
module MyApp
class User < ApplicationRecord
...
end
end
and if I put it in app/models/myapp Rails finds it. However, since all my models will be within the MyApp module I'd rather keep them in app/models.
Thanks
No, you can't tell Rails to look for a qualified constant (like MyApp::User) at the top level of a directory in the autoload path like (app/models). When Rails sees MyApp::User (in code which is not inside a module definition) it will only look for my_app/user.rb in directories in the autoload path.
You could trick Rails a lot of the time by never using qualified constants. If your controllers are in the same namespace, the following would work:
app/controllers/my_app/users_controller.rb
module MyApp
class UsersController < ApplicationController
def index
#users = User.all
end
end
end
app/models/user.rb
module MyApp
class User < ActiveRecord::Base
end
end
Rails doesn't know whether the User referenced in the controller is top-level or in MyApp, so it would look for both app/models/user.rb and app/models/my_app/user.rb. Similarly, you could autoload namespaced models in app/models from other namespaced models.
However, you'd hit a wall (that is, you'd have to manually require the model class file) as soon as you needed to refer to a namespaced model from code which was not itself in a namespace, e.g. in the console or in a unit test. And it would be silly to have controllers in a subdirectory but models not in a subdirectory. And you'd be confusing anyone who looked at your code. So the best thing to do would be to follow Rails convention and put your namespaced models in a subdirectory of app/models.
Can I have controllers in Rails that are 3 levels deep inheritance? One would think such a trivial thing is possible, but the concrete controller at the "third" level gives the generic/useless error of "uninitialized constant Ns2::SecondController"
This is basically with this code (I haven't tried this exact code)
module Ns3
class ThirdController < Ns2::SecondController
end
end
module Ns2
class SecondController< Ns1::FirstController
end
end
module Ns1
class FirstController< ApplicationController
end
end
NOTE: The use of namespaces, within the routes and all such directories should be set up properly.
I'm sure I could rearrange the logic and get something working with mixins or helpers. However, I'd like the immediate question answered for my own benefit. Either Y/N or a way passed the error. Not interested in a refactoring work-around solution ATM. Though I guess it couldn't hurt.
Thanks
This can be done.
However it appears RoR is weird, and that you have to implicitly specify the namespace for base classes. If you let it default to the current namespace it acts weird.
Its most likely a typo in either the class name or filename.
You need to put the classes in the correct file/directory structure for Rails autoloading to work, e.g:
#/controllers/ns3/third_controller.rb
module Ns3
class ThirdController < Ns2::SecondController
end
end
#/controllers/ns2/second_controller.rb
module Ns2
class SecondController < Ns1::FirstController
end
end
#/controllers/ns1/first_controller.rb
module Ns1
class FirstController < ApplicationController
end
end
Another thing to try is scoping from the root namespace so with a :: prefix, like so:
module Ns1
class SecondController < ::Ns1::FirstController
end
end
You could also try this:
#/controllers/ns3/third_controller.rb
class Ns3::ThirdController < ::Ns2::SecondController
end
I'm migrating the majority of my application to the admin namespace and while there are lots of guides related to this, I still can't manage. I've been primarily following this answer, along with any results Google brings up (they all tend to agree). Could somebody please tell me what I'm doing wrong so I don't lose any more sleep?
Here is the error message:
wrong argument type Module (expected Class)
app/controllers/application_controller.rb:1:in `<top (required)>'
app/controllers/admin/admin_controller.rb:1:in `<top (required)>'
app/controllers/admin/home_controller.rb:1:in `<top (required)>'
routes.rb
namespace :admin do
root :to => "home#index"
resources :users
end
admin/admin_controller.rb
class Admin::AdminController < ApplicationController
admin/home_controller.rb
class Admin::HomeController < Admin::AdminController
admin/users_controller.rb
class Admin::UsersController < Admin::AdminController
I'm mostly sure it's something simple to related to the module and controller interaction, so I haven't included any other code. However, I should have found the solution by now and please let me know if any additional code is required.
Thanks.
I encountered the reverse problem "wrong argument type Class (expected Module)" and it turned out there was a helper defined as a Class instead of a Module, so try searching for classes that are inadvertently defined as modules. Like a controller defined as a Module.
I'd suggest you rename Admin::AdminController to Admin::BaseController.
Maybe you have something defined as Admin constant?
Try a fresh app with the same structure then add pieces from the current one and see where it breaks (Not so great suggestion, huh?).
I use the same organization for admin as you pasted...
"wrong argument type Module (expected Class)"
This means you are defining a 'class' but that name is already defined as a 'module' somewhere else. Search for what that could be...
Can u follow the below code, Your controllers are fine, can you use the routes I have specified here.
class Admin::AdminController < ApplicationController
class Admin::UsersController < Admin::AdminController
This is same as what you have written, I think so.
namespace :admin do
resources :users do as_routes end
end
root :to => "home#index"
#Russell, I got that problem having created model AdminHelper (meant to contain admin help messages) :)
be careful in naming things!
I encountered such problem when I used paperclip's has_attached_file with invalid parameters.
Everytime i get a warning:
app/controllers/agency/agencies_controller.rb:1: warning: toplevel constant ApplicationController referenced by Agency::ApplicationController
My agencies_controller.rb:
class Agency::AgenciesController < Agency::ApplicationController
def index
...
end
...
end
And Agency::ApplicationController:
class Agency::ApplicationController < ApplicationController
layout 'agency'
helper_method :current_agency
private
def current_agency
#current_agency ||= current_user.agency
end
end
What the rails wants from me? What is the trouble?
Same situation with another controller
class Agency::ClientsController < Agency::ApplicationController
...
end
And no warnings, no errors...
I realize this question is almost two years old but I recently stumbled upon this through another stackoverflow post and wanted to share some insight.
Basically, if your namespace Agency happens to be a class instead of a module, you'll get that warning. In the stackoverflow post I pasted above, they had a model (class) of Admin and their namespace was also Admin.
This provides a better explanation of what is happening.
So check to see if your code isn't defining an Agency class somewhere. Good luck.
I had similar issues running Spork and Watchr in my Admin namespaced controllers. So i've fixed this by adding following code into each_run block in spec_helper.rb:
Dir[File.expand_path("app/controllers/admin/*.rb")].each do |file|
require file
end
All credits goes to guy from this thread
ApplicationController is the name of the superclass controller that Rails generates for you when you create a new project that all your other controller classes inherit from. There's probably a conflict somewhere because you've used the same name, even though you put it within a namespace.
Try giving your Agency::ApplicationController a different name.
I had similar issues, after setting up Spork and Watchr. In the process, I turned off class cacheing (config_cache_classes => false in config/environments/test.rb) so that changes would be reloaded as necessary in the spork environment. Turning class cacheing back on made the warnings go away.
In my case it was the problem with Devise. I had a devise model Admin and a namespaced routes Admin. Changing the namespaced route to Admins solved the problem.
Solution for me was add this line:
# spec/rails_helper.rb
Dir[File.expand_path("app/controllers/admin/*.rb")].each { |file| require file }