Previously I had my middleware under lib/middleware/my_middle_ware.rb
However when doing this,
config.middleware.use MyMiddleWare
I receive a
NameError: uninitialized constant
Where is rails looking for the middleware?
Look like rails wasn't looking for it.
I had to do the following for it to work.
Dir["./lib/middleware/*.rb"].each do |file|
require file
end
Create a folder app/middlewares and create your middleware file in this folder.
But unfortunately The app/middlewares folder is not loading even if I added to the load paths in Rails v5.2.2
config.autoload_paths << "#{Rails.root}/app/middlewares"
config.eager_load_paths << "#{Rails.root}/app/middlewares"
So you can use require explicitly as follows, add this line in application.rb
require_relative '../app/middlewares/my_middleware'
and load middleware:
config.middleware.use MyMiddleware
and call rake middleware to see the middleware stack.
I believe you want to add your middleware to either your config/application.rb or your config/environments file.
config.middleware.use MyMiddleWare
This should work and append MyMiddleWare to the bottom of the middleware stack.
Even before app/middleware contents are loaded if 'config.middleware.use' is called, I think you get the 'uninitialized Constant error'. The below should fix
config.middleware.use "MyMiddleWare"
If the above doesn't work, one of the below might be a no.
Is MyMiddleWare in app/middleware/my_middle_ware.rb ?
Is MyMiddleWare in lib/my_middle_ware.rb ?
replacing middleware as a string in config/application.rb to config/environment/{environment} as a constant fixed the issue for me
Related
Rails loads files from app/models/concerns and app/controllers/concerns directly into the global namespace instead of the Concerns namespace.
So if you define a module SomeConcern at app/models/concerns/some_concern.rb, instead of Concerns::SomeConcern, you have just SomeConcern available.
I would like to add a concerns folder in another subdirectory of app that behaves the same way. More specifically: I want to define SomeSerializerConcern at app/serializers/concerns/some_serializer_concern.rb, but currently it's only working if I define the module as Concerns::SomeSerializerConcern.
I have this line in config/application.rb:
config.paths.add "app/serializers/concerns", eager_load: true
This excellent post on autoload and eager_load led me to believe that this is how Rails itself accomplishes what I want to do, but it doesn't seem to work in this scenario. I'm using Rails 4.2.6. Any ideas?
Turns out this gist provides the answer.
All I needed to do was add the path directly to eager_load_paths in config/application.rb:
config.eager_load_paths += [Rails.root.join('lib'),
Rails.root.join('app', 'serializers', 'concerns')]
It looks like this issue will be solved in Rails 4:
http://blog.plataformatec.com.br/2012/08/eager-loading-for-greater-good/
but until then, I'm wondering how to eager-load modules/classes in my /lib.
In IRB it appears that they are loaded on-demand the first time I try to access:
Foo::Bar.constants
=> []
Foo::Bar::Service
=> Foo::Bar::Service
Foo::Bar.constants
=> [:ServiceBase, :Service]
I have several other classes in that module, and my code depends on being able to look them up using Foo::Bar.const_defined? at runtime - how do I ensure all Foo::Bar's classes get loaded at startup?
I'm already using config.autoload_paths += %W(#{config.root}/lib) in application.rb.
Putting this in root/config/initializers/eager.rb should load all .rb files in that folder:
Dir["#{Rails.root}/lib/*.rb"].each {|file| load file}
For me putting this in application.rb solved the problem
config.eager_load_paths += Dir["#{config.root}/lib/**/"]
Use eager_load_paths combined with ActiveSupport::Reloader's to_prepare hook inside development.rb:
config.eager_load_paths += Dir["app/models/stimodel/**/*.rb"]
ActiveSupport::Reloader.to_prepare do
Dir["app/models/stimodel/**/*.rb"].each { |f| require_dependency("#{Dir.pwd}/#{f}") }
end
Adding your paths to eager_load_paths make sure that Rails loads them when it starts up. To make sure that Rails reloads our models if we do any changes or add new files, we also need to hook into the Reloader's to_prepare hook and manually require the dependency there.
i am using delayed_job 2.1.0.pre2,
and in my lib i have a class which named MailingJob(mailing_job.rb),and it has one method named perform.
In my controller , i put a new MailingJob object in my delayed_job queue as the doc said.
but when i run the "rake jobs:work" command,it always told me that it can't find "MailingJob", is it necessary to require the mailing_job.rb file?if yes,where should i put this?
thanks!
mailing_job.rb must be in a place where Rails can find and auto-load it. Where do you have that file? Unless it's in app/models or something like that, it won't find it on its own.
I have my jobs in app/jobs but this works because I added that path to the Rails load paths in the environment.rb Rails::Initializer.run block:
config.load_paths << "#{Rails.root}/app/jobs"
Nowadays in Rails 6.1 I had to put it in the application.rb as follows:
config.autoload_paths << Rails.root.join('/app/jobs')
I place a file name g.rb in side Rails.root/lib folder
The file content is like this:
module Google
end
Then I add
config.autoload_paths += %W(#{config.root}/lib #{Rails.root}/app/delayed_jobs)
to my Rails.root/config/application.rb
However, when I try to invoke Google from rails console, an exception is thrown. The exception goes away only if I execute require 'google'.
Why? Shouldn't my file is autoloaded and shouldn't I access the module without any extra require statement?
Hmm, I discovered an interesting thing. In order for Rails to auto load my class, the class name should be compliant to the file name and the folder structure.
For example, if I want to have Google module autoloaded, I must placed it inside google.rb, directly under /lib (incase I specify autoload from /lib).
If I want to auto load Google::Docs, then I either place it inside google.rb or google/docs.rb
I had a similar problem with getting my module to run on Heroku. In addition to the autoload naming convention stated by Stephen C, I found out that the module code must be require'd due to a threadsafe assumption made by the Rails' production environment on Heroku (even though threadsafe was commented out in my production.rb configuration file.) As soon as I require'd the module file before calling include on the module, everything started to work.
require 'mymodule'
include Mymodule
Please take a look at this excellent article on the subject of getting Modules to load correctly in Heroku (production).
That's because the point of autoload is not to 'require' everything up front (startup penalty). Classes are loaded as they are needed/referenced. In order to do this, you need some way to know where to look for the class. Otherwise, you would have to load every file in the autoload directory in advance to see what classes are declared. It's a tradeoff, but requiring everything in advance (as marbaq suggests) is not autoloading.
You can use the autoload command as provided by Ruby, which takes two arguments, the module to load (symbolized, i.e. :Google in your case), and the second argument is the filename, which would be g.rb if lib is in your load path ($:). See the Ruby docs for autoload.
Change config.autoload_paths to config.eager_load_paths
(based on Rails issue #6850 and Force reload! from lib directory in rails 3.2 console)
I faced the same problem just now, and my "solution" (or rather workaround) was to manually require every needed file from Rails.root/lib in my application.rb.
require 'lib/message'
require 'lib/store'
require 'lib/vault/vault.rb'
require 'lib/custom_loggers'
module MyApplication
class Application < Rails::Application
My next step would be to categorize the files in module folders as you mention.
i found this solution recently
config/application.rb
module AppName
class Application < Rails::Application
# Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += Dir[Rails.root.join('app', 'models', '{**}')]
config.autoload_paths += Dir[Rails.root.join('app', 'lib', 'extensions')]
end
end
the first config call induces rails to auto-load all sub-directories of the app/models directory
so now i can have /app/models/sub_directory/model.rb auto-loaded
(handy for organising an app with a large code base)
the second config call induces rails to autoload the lib/extensions directory
hope this helps
note: i believe this is rails 3 specific
I'm in the process of refactoring some logic built into a Rails application into middleware, and one annoyance I've run into is a seeming lack of convention for where to put them.
Currently I've settled on app/middleware but I could just as easily move it to vendor/middleware or maybe vendor/plugins/middleware...
The biggest problem is having to require the individual files at the top of config/environment.rb
require "app/middleware/system_message"
require "app/middleware/rack_backstage"
or else I get uninitialized constant errors on the config.middleware.use lines. That could get messy very quickly. I'd rather this was tucked away in an initializer somewhere.
Is there a conventional place to put this stuff?
The specific answer I'm looking for with this bounty is: where can I put the require lines so that they are not cluttering the environment.rb file but still get loaded before the config.middleware.use calls? Everything I have tried leads to uninitialized constant errors.
Update: Now that we're using Rails 3.0, I treat a Rails app like any other Rack app; code files for middleware go in lib (or a gem listed in Gemfile) and are required and loaded in config.ru.
As of Rails 3.2, Rack middleware belongs in the app/middleware directory.
It works "out-of-the-box" without any explicit require statements.
Quick example:
I'm using a middleware class called CanonicalHost which is implemented in app/middleware/canonical_host.rb. I've added the following line to production.rb (note that the middleware class is explicitly given, rather than as a quoted string, which works for any environment-specific config files):
config.middleware.use CanonicalHost, "example.com"
If you're adding middleware to application.rb, you'll need to include quotes, as per #mltsy's comment.
config.middleware.use "CanonicalHost", "example.com"
You can put it in lib/tableized/file_name.rb. As long as the class you're trying to load is discoverable by its filename, Rails will automatically load the file necessary. So, for example:
config.middleware.use "MyApp::TotallyAwesomeMiddleware"
You would keep in:
lib/my_app/totally_awesome_middleware.rb
Rails catches const_missing and attemts to load files corresponding to the missing constants automatically. Just make sure your names match and you're gravy. Rails even provides nifty helpers that'll help you identify the path for a file easily:
>> ChrisHeald::StdLib.to_s.tableize.singularize
=> "chris_heald/std_lib"
So my stdlib lives in lib/chris_heald/std_lib.rb, and is autoloaded when I reference it in code.
In my Rails 3.2 app, I was able to get my middleware TrafficCop loading by putting it at app/middleware/traffic_cop.rb, just as #MikeJarema described. I then added this line to my config/application.rb, as instructed:
config.middleware.use TrafficCop
However, upon application start, I kept getting this error:
uninitialized constant MyApp::Application::TrafficCop
Explicitly specifying the root namespace didn't help either:
config.middleware.use ::TrafficCop
# uninitialized constant TrafficCop
For some reason (which I've yet to discover), at this point in the Rails lifecycle, app/middleware wasn't included in the load paths. If I removed the config.middleware.use line, and ran the console, I could access the TrafficCop constant without any issue. But it couldn't find it in app/middleware at config time.
I fixed this by enclosing the middleware class name in quotes, like so:
config.middleware.use "TrafficCop"
This way, I would avoid the uninitialized constant error, since Rails isn't trying to find the TrafficCop class just yet. But, when it starts to build the middleware stack, it will constantize the string. By this time, app/middleware is in the load paths, and so the class will load correctly.
For Rails 3:
#config/application.rb
require 'lib/rack/my_adapter.rb'
module MyApp
class Application < Rails::Application
config.middleware.use Rack::MyAdapter
end
end
I'm not aware of a convention, but why not put it in the /lib directory? Files in there get automatically loaded by Rails.
You could create an initializer which requires the necessary files and then leave the files wherever you want.
According to this the initializers are executed before the rack middleware is loaded.
The working solution I have so far is moving the middleware requires to config/middleware.rb and requiring that file in environment.rb, reducing it to a single require which I can live with.
I'd still like to hear how other people have solved this seemingly basic problem of adding middleware to Rails.