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')
Related
I have Rails 6, my preview class located in
mailer/previews/devise_mailer_preview.rb:
class DeviseMailerPreview < ActionMailer::Preview
...
end
And when I run application locally, everything is going fine, I can see my email previews on http://localhost:3000/rails/mailers/devise_mailer/confirmation_instructions address. But now Im trying to deploy application on server, and found that when I run bundle exec rails c production, I got the error:
/home/deploy/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/zeitwerk-2.3.0/lib/zeitwerk/loader/callbacks.rb:17:in
`on_file_autoloaded': expected file
/home/deploy/project/releases/20200627024908/app/mailer/previews/devise_mailer_preview.rb
to define constant Previews::DeviseMailerPreview, but didn't
(Zeitwerk::NameError)
After that I've checked locally RAILS_ENV=production rails c, and got same.
If I will rename DeviseMailerPreview class to Previews::DeviseMailerPreview, it will be broken and I cannot see emails on development, because Rails 6, accordingly to docs, expect exactly that name.
More of that, I've found in this article, that zeitwerk can be configured with autoload_paths param to avoid ruby's NameError. I found that I have it my config/application.rb:
config.load_defaults 6.0
Anyway I tried to add same row in my config/environments/production.rb file, but it didn't help.
What am I doing wrong and how can I fix it? Thanks in advance!
Add preview_path to the autoload_paths and zeitwerk will expect DeviseMailerPreview constant to be defined.
# development.rb
config.action_mailer.preview_path = Rails.root.join("app/mailers/previews")
# application.rb
config.autoload_paths << Rails.root.join("app/mailers/previews")
Your Mailer preview file is located in mailer/previews/devise_mailer_preview.rb, so I'm assuming it's full path is app/mailer/previews/devise_mailer_preview.rb
The docs says
In the above example, the preview class for UserMailer should be named UserMailerPreview and located in test/mailers/previews/user_mailer_preview.rb
So put your devise_mailer_preview.rb file to test/mailers/previews/devise_mailer_preview.rb
or in your config/application.rb add this line and restart:
config.action_mailer.preview_path = "#{Rails.root}/app/mailers/previews"
Actually the answer was in the docs itself.
In Rails 6, previews are added to the autoload paths only if options.show_previews is true, which is not by default in the production environment. See the source code here.
The reason for this is that previews are supposed to be an aid for development, and they are generally not something you want to be able to look at in production.
However, you can set that flag to true in production if you want.
There's another derivative: By storing the previews under app/mailers, Rails is going to eager load them because app/mailers is in the autoload paths. If app/mailers/previews is not in the autoload paths, eager loading will fail due to the namespace mismatch. Either you have them enabled in all environments, or else is better to have them in a separate location, like the default.
I am running a Rails application.
app/workers/sample/fetch_book_report_worker.rb
class Sample::FetchBookReportWorker
// body
end
app/workers/sample/fetch_student_report_worker.rb
class Sample::FetchStudentReportWorker
// body
end
app/workers/sample/fetch_teacher_report_worker.rb
class Sample::FetchTeacherReportWorker
// body
end
app/workers/sample/fetch_college_report_worker.rb
class Sample::FetchCollegeReportWorker
// body
end
When I ran the above worker individually, I didn't see an issue. But I ran all the workers at the same time. I got the below error.
LoadError: Unable to autoload constant Sample::FetchStudentReportWorker, expected /home/ubuntu/my-app/app/workers/sample/fetch_student_report_worker.rb to define it
How to solve this?
You can see autoload_paths to type this command.
bin/rails r 'puts ActiveSupport::Dependencies.autoload_paths'
If you can't see .../app/workers/sample, add the autoload_paths in config/application.rb
config.autoload_paths << Rails.root.join("app/workers/sample")
If it could causes problem in production mode, use the 'eager_load_paths'
referece from https://guides.rubyonrails.org/autoloading_and_reloading_constants.html
One likely root cause for the LoadError error is, that as of Rails 5.2.0, there are changes to autoload, that require submodules (namespaces) to (at the least) be defined (as a constant).
In the original post's example, the module Sample should be defined in the app/workers/sample.rb file (as commented by Vasfed above).
Refer to this related SO answer for more details.
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
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.
As of Rails 2.3, what's the right way to add a directory to the load path so that it hooks into Rails' auto-reloading mechanisms?
The specific example I'm thinking of is I have a class that has several sub-classes using STI and I thought it would be a good idea to put them in a sub-directory rather than clutter the top-level. So I would have something like:
#app/models/widget.rb
class Widget < ActiveRecord::Base
add_to_load_path File.join(File.dirname(__FILE__), "widgets")
end
#app/models/widgets/bar_widget.rb
class BarWidget < Widget
end
#app/models/widgets/foo_widget.rb
class FooWidget < Widget
end
It's the add_to_load_path method that I'm looking for.
In the current version of Rails (3.2.8), this has been changed in the application.rb file.
The code is currently commented out as:
# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
Will need to update the autoload_paths value. Attempting to modify the the former load_paths variable causes this error.
/configuration.rb:85:in `method_missing': undefined method `load_paths' for #<Rails::Application::Configuration:0xac670b4> (NoMethodError)
for an example, for each path to add to autoload_paths config, add a line similar to the following:
config.autoload_paths += %W(#{config.root}/app/validators)
config.autoload_paths accepts an array of paths from which Rails will autoload constants. Default is all directories under app.
http://guides.rubyonrails.org/configuring.html
From commentor (hakunin) below:
If the directory is under app/, you don't need to add it anywhere, it should just work by default (definitely in 3.2.12). Rails has eager_load_paths that acts as autoload_paths in development, and eager load in production. All app/* directories are automatically added there.
For older versions of Rails:
You can do this in your environment.rb config file.
config.load_paths << "#{RAILS_ROOT}/app/widgets"
--
For Rails 3, see answers bellow
In Rails 5 you don't have to explicitly load folders from within the app directory anymore. All folders placed inside are directly available. You don't have to touch any of the config files. But it seems as if there are some issues with Spring.
The new workflow therefore is:
create a new folder and class inside the /app directory
run spring stop on the command line
check the autoload-paths with bin/rails r 'puts ActiveSupport::Dependencies.autoload_paths' on the command line. The new folder should now be listed.
run spring start on the command line
In Rails 3, you can set this in config/application.rb, where this sample is provided by default:
# Add additional load paths for your own custom dirs
# config.load_paths += %W( #{config.root}/extras )
On Rails 5 you need to add the following code to environment.rb:
# Add the widgets folder to the autoload path
Rails.application.configure do
config.autoload_paths << "#{Rails.root}/app/widgets"
end
Another update for rails 3 -- activesupport 3.0.0:
Instead of:
ActiveSupport::Dependencies.load_paths << "#{RAILS_ROOT}/app/widgets"
You may need to do this:
ActiveSupport::Dependencies.autoload_paths << "#{RAILS_ROOT}/app/widgets"
I found I needed to do this after config block-- no access to config object anymore.
This did the trick
ActiveSupport::Dependencies.load_paths << "#{RAILS_ROOT}/app/widgets"
In config/application.rb add config.autoload_paths << "#{config.root}/models/widgets".
File should look like this:
module MyApp
class Application < Rails::Application
config.autoload_paths << "#{config.root}/models/widgets"
end
end
I know this works for Rails 4 and 5. Probably others as well.
If you want to add multiple directories:
config.autoload_paths += Dir[Rails.root / "components/*/app/public"]
(this is an example for packwerk autoload)