Rails3: warning: toplevel constant ApplicationController referenced by - ruby-on-rails

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 }

Related

uninitialised constant after upgrade of Gemfile

I've just updated my Gemfile.
At the beginning I thought problem came from Zeitwerk (from 2.4.2 to 2.5.4) but I've downgraded it and I still have an issue on my spec. I've isolated that the problem does not come from RSpec and dependencies.
Actually, RSpec does not found a class which is defined within another file and does not match the file name/class name.
Important point: Filter::MyStandardError is found.
# app/services/filter/my_standard_error.rb
module Filter
class MyStandardError < StandardError; end
class MySpecificError < MyStandardError; end
# ...
end
# app/services/filter/my_tested_service.rb
module Filter
class MyTestedService
def initialize
raise ::Filter::MySpecificError
end
end
end
RSpec.describe Filter::MyTestedService do
subject { described_class.new }
it 'raises an error'
expect{subject}.to raise_error(::Filter::MySpecificError)
end
end
And I got the error:
NameError:
uninitialized constant Filter::MySpecificError
I got the Changelog but breaking changes are not used on my configuration.
Does anybody have an idea for this one?
You do not need to add app/services to the autoload paths, that is done automatically by Rails. I'd suggest to remove that configuration to keep things simple/idiomatic.
The implementation of app/services/filter.rb should not be needed. Your application is doing something that is not right, we just need to find it.
Could you please delete app/services/filter.rb, throw Rails.autoloaders.log! in config/application.rb, trigger the error, and share the traces?
After reading one-file-one-constant-at-the-same-top-level
I found this to fix my issue
# app/services/filter.rb
class Filter
class MyStandardError < StandardError; end
class MySpecificError < MyStandardError; end
end
# app/services/filter/my_tested_service.rb
class Filter
class MyTestedService
def initialize
raise ::Filter::MySpecificError
end
end
end
I still don't know why it was working before..
You cannot define two constants at the same level in the same file. It is one constant, one file. This has not changed in Zeitwerk upgrades. You need one file for the standard error, and another file for the specific error.

Rails and RSpec: Testing controllers with the same name in different namespace (module)

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).

Rails - proper way to create admin section (`module` or `Admin::`)?

I'm new in Ruby and RoR and I'd like to create an admin section for a demo app.
From a little research I've done I've found two different options for creating an admin section. Example:
# config/routes.rb
namespace :admin do
resources :users
end
# app/controllers/admin_controller.rb
class AdminController < ApplicationController
before_filter :authorized?
...
end
Which of the two options is the most proper way to define controllers for the admin section, or they are both equally same?
# app/controllers/admin/users_controller.rb
# I think this is what rails generates if I run the "rails g controller admin::users" command
class Admin::UsersController < AdminController
...
end
# or instead
module Admin
class UsersController < AdminController
....
end
end
Both approaches yield to the same result, which is an UsersController which inherits from AdminController and is found in the Admin module (namespace).
Admin::MyClass is just a shortcut for module Admin ... class MyClass, but...
I would however prefer the explicit nested code (with module Admin on its own line), because it does make a different if the Admin-module has never been defined before. This probably won't happen to you when hacking with standard rails, but can happen when you write ruby code outside of rails.
See these examples:
class I::Am::AClass
end
i = I::Am::AClass.new
puts i.inspect
will lead to
i.rb:1:in `<main>': uninitialized constant I (NameError)
if you never declared the I and nested Am modules before in your code.
Whereas
module I
module Am
class AClass
end
end
end
i = I::Am::AClass.new
puts i.inspect
will work:
#<I::Am::AClass:0x00000001d79898>
because the modules are created along the path to AClass (at least this is how I think about it).
If you ever run in that problem and want to save whitespaces (because you will usually indent stuff in a module definition), there are some idioms to use. The one that solves the problem in the most obvious way (again, to me) is the following:
# Predefine modules
module I ; module Am ; end ; end
# Just a shortcut for:
# module I
# module Am
# end
# end
class I::Am::AClass
end
i = I::Am::AClass.new
puts i.inspect
#<I::Am::AClass:0x000000024194a0>
Just found that the nature of your question (it is not about an Admin-Interface, more about Module-Syntax) is also nicely discussed here Ruby (and Rails) nested module syntax . And I would love to see a ruby-bug report/feature-request on this :)
You can also use the administration framework for Ruby on Rails applications like
ActiveAdmin https://github.com/activeadmin/activeadmin
OR
Railsadmin
https://github.com/sferik/rails_admin

Rails - URL helpers not working in mailers

I tried:
class MyMailer
def routes
Rails.application.routes.url_helpers
end
def my_mail
#my_route = routes.my_helper
... code omitted
end
Also inside mailer:
include Rails.application.routes.url_helpers
def my_mail
#my_route = my_helper
Also, the simple way, in mailer template:
= link_to 'asd', my_helper
But then when I try to start console I get:
undefined method `my_helper' for #<Module:0x007f9252e39b80> (NoMethodError)
Update
I am using the _url form of the helper, i.e. my_helper_url
For Rails 5, I included the url helpers into the my mailer file:
# mailers/invoice_mailer.rb
include Rails.application.routes.url_helpers
class InvoiceMailer < ApplicationMailer
def send_mail(invoice)
#invoice = invoice
mail(to: #invoice.client.email, subject: "Invoice Test")
end
end
Doing this broke my other routes.
# mailers/invoice_mailer.rb
include Rails.application.routes.url_helpers
Doing this is not the right way, this will break application as routes are reloading and routes will not be available is those are reloading
module SimpleBackend
extend ActiveSupport::Concern
Rails.application.reload_routes!
Right answer is to use *_url and not *_path methods in email templates as explained below in Rails docs.
https://guides.rubyonrails.org/action_mailer_basics.html#generating-urls-in-action-mailer-views
I ran into the same issue but with a Concern, i was unable to use any of the url helpers in my code even using directly Rails.application.routes.url_helpers.administrator_beverages_url i was getting this error:
undefined method `administrator_beverages_url' for #<Module:0x00000002167158> (NoMethodError)
even unable to use the rails console because of this error the only way i found to solve this was to use this code in my Concern
module SimpleBackend
extend ActiveSupport::Concern
Rails.application.reload_routes! #this did the trick
.....
The problem was Rails.application.routes.url_helpers was empty at the moment of the initialization. I don't know the performance implication of using this but for my case this is a small application and i can take the bullet.
In the mailer add
helper :my
or the helper you need
and it will load app/helpers/my_helper.rb & includes MyHelper
Enjoy
The rails route helpers are in Rails.application.routes.url_helpers. You should just be able to put
include Rails.application.routes.url_helpers at the top of your class, though I haven't tested this
I came across this issue while working with a newly added route that seemed to be unavailable in my Mailer. My problem was I needed to restart all the workers, so they would pick up the newly added route. Just leaving this footnote in here in case someone runs into the same issue, it can be tricky to solve if you don't know this is happening.
Please take a look at this blog which explains how you can make use of Rails.application.routes.url_helpers in the right manner.
http://hawkins.io/2012/03/generating_urls_whenever_and_wherever_you_want/
You need to use the my_helper_url

How to extend a mountable engine's model inside another mountable engine with development environment reloading

Using Rails 3.2.2 and Ruby 1.9.2.
I have a rails mountable engine EngineA that declares a User class inheriting form ActiveRecord::Base. I have another engine EngineB that wants to inject functionality into EngineA::User. Right now what I have done is shown below:
Method 1:
#EngineA app/models/engine_a/user.rb
module EngineA
class User < ActiveRecord::Base
has_attached_file :avatar
has_many :somethings
end
end
#EngineB lib/engine_b/user.rb
module EngineB
module User
def self.extended obj
obj.class_eval do
has_many :something_elses
end
end
end
end
EngineA::User.extend EngineB::User
This gives me an uninitialized constant EngineA::User error. Even when I require that specific file I run into the problem of EngineA needing paperclip so that has_attached_file is understood. That road ended when I realized I would have to know and require the dependencies for EngineA inside EngineB.
Method 2:
I used the same code as before except I removed the last line EngineA::User.extend EngineB::User from the EngineB user.rb file. I then moved that call to an initializer inside EngineB.
#EngineB config/initializers/my_mixin.rb
EngineA::User.extend EngineB::User
This worked perfectly!!! Except in development mode when I would change code and the models would refresh. The only thing that was refreshed was the EngineA::User and not the mixin that I had put as an initializer. So once I changed code, I lost all of my extended functionality.
I'm not even positive this is the most 'efficient' way to do this... any help would be greatly appreciated. Thanks in advance.
According to the configuration documentation, you can use an ActionDispatch callback to load items. These callbacks will run when at every request if cache_classes is set to false, like in development mode.
Inside of your EngineB.rb file, you might try something like this:
if Rails.env.development?
ActionDispatch::Callbacks.to_prepare do
load "#{File.expand_path(File.dirname(__FILE__))}/../config/initializers/my_mixin.rb"
end
end

Resources