I have this rake task in a Rails 3.2.11 application in lib/rake/searches.rb:
namespace :searches do
desc "Start background searches"
task :start => :environment do
Rails.logger.info "Starting searches..."
Campaign.all.each do |c|
next unless c.recurring?
Rails.logger.info "Starting searches for campaign '#{c.name}'"
SearchWorker.enqueue(:campaign_id => c.id, :clear => true)
end
end
end
When I run it locally everything goes well. When I run it in production it errors out:
$ bundle exec rake searches:start
rake aborted!
uninitialized constant SearchWorker
/var/apps/web/lib/tasks/searches.rake:9:in `block (3 levels) in <top (required)>'
/var/apps/web/lib/tasks/searches.rake:5:in `block (2 levels) in <top (required)>'
Tasks: TOP => searches:start
(See full trace by running task with --trace)
When I jump into a console session, I can see that the class is correctly auto loaded:
$ bundle exec rails console
Loading production environment (Rails 3.2.11)
irb(main):001:0> SearchWorker
=> SearchWorker
This workers live in app/workers and they are added to the autoload_paths config setting in application.rb:
# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
config.autoload_paths += %W(
#{config.root}/custom_scripts
#{config.root}/app/workers
#{config.root}/app/models/filters
)
So I have no clue why the error only occurs in production, and when running from a rake task.
Any ideas?
It seems you have created the rake file with .rb extension
lib/rake/searches.rb
can you try changing it to
lib/rake/searches.rake
That should work
This is due to the production environment in Rails 3.2 not being fully loaded, after the :environment task is complete.
If you explicitly require SearchWorker ie.
require 'app/workers/search_worker'
Within the beginning of the task block, it'll work.
(Why auto-loads isn't doing this for you, I don't know)
Related
On Rails 6 (6.1.4.1) we had a RakeFile that would run a subset of tests. For example:
# lib/tasks/carrier.rake
namespace :test do
task carriers: "test:prepare" do
$: << "test"
test_files = FileList["test/models/carrier_test.rb",
"test/controllers/admin/carriers/**/*_test.rb",
"test/system/admin/carriers/**/*_test.rb"]
Rails::TestUnit::Runner.run(test_files)
end
end
This would execute just fine when called:
rails test:carriers
However, somewhere along the way, something changed and we began seeing errors when trying to run our RakeFile test tasks. (I haven't tracked down exactly what changed and when it changed -- perhaps it was part of the Rails 7 release.) Here's the error we began seeing:
rails aborted!
NameError: uninitialized constant Shoulda
Shoulda::Matchers.configure do |config|
^^^^^^^
/path/test/test_helper.rb:15:in `<main>'
/path/test/models/carrier_test.rb:1:in `<main>'
/path/lib/tasks/carriers.rake:11:in `block (2 levels) in <main>'
Tasks: TOP => test:carriers
(See full trace by running task with --trace)
The error appeared with no changes to our tests or environment configuration. (Running a full rake worked just fine.)
When reviewing the source code for Rails::TestUnit::Runner, I came across rake_run. Simply replacing Rails::TestUnit::Runner.run with Rails::TestUnit::Runner.rake_run addressed the issue (no other changes required):
# lib/tasks/carrier.rake
namespace :test do
task carriers: "test:prepare" do
$: << "test"
test_files = FileList["test/models/carrier_test.rb",
"test/controllers/admin/carriers/**/*_test.rb",
"test/system/admin/carriers/**/*_test.rb"]
Rails::TestUnit::Runner.rake_run(test_files)
end
end
I have a task that want to run after I run rails tmp:clear
namespace :myapp do
task :clear do
# do some stuff
end
end
I've learned that I can do it by enhancing that task:
Rake::Task['tmp:clear'].enhance(['myapp:clear'])
The problem is that when my code is loaded, tmp:clear is undefined, so it fails:
$ rails tmp:clear
rails aborted!
Don't know how to build task 'tmp:clear' (See the list of available tasks with `rails --tasks`)
myapp/lib/tasks/clear.rake:7:in `<top (required)>'
Rails tasks are loaded after local tasks. You need to require 'rails/tasks' before to circumvent that.
Complete solution:
require 'rails/tasks'
namespace :myapp do
task :clear do
puts "do some stuff"
end
end
Rake::Task['tmp:clear'].enhance(['myapp:clear'])
The following command is supposed to create a new database.
rails db:create
Where is this function defined? Or is this a pre-packaged function in rails?
It's in the databases.rake file of the framework:
namespace :create do
task all: :load_config do
ActiveRecord::Tasks::DatabaseTasks.create_all
end
ActiveRecord::Tasks::DatabaseTasks.for_each do |spec_name|
desc "Create #{spec_name} database for current environment"
task spec_name => :load_config do
db_config = ActiveRecord::DatabaseConfigurations.config_for_env_and_spec(Rails.env, spec_name)
ActiveRecord::Tasks::DatabaseTasks.create(db_config.config)
end
end
end
Whenever you doubt or want to know where a task has been defined, you can use the rails -W (or rake) command, passing the task:
$ rails -W db:create
rails db:create /path/databases.rake:26:in `block in <top (required)>'
rails db:create:all /path/databases.rake:20:in `block (2 levels) in <top (required)>'
Note it was introduced in the version 0.9 of Rake. This might or might not work depending on the versions which you're working with.
In a Rails 4 app, I want precompiled assets to have copies of some assets to be available with a non fingerprinted filename. The app is deployed on Heroku.
I have the following rake task in place:
namespace :app do
task :nonfingerprint_assets => :environment do
manifests = Rails.application.config.assets[:precompile]
manifests = manifests.slice(1, manifests.length)
assets = Dir.glob(File.join(Rails.root, 'public/assets/**/*'))
regex = /(-{1}[a-z0-9]{32}*\.{1}){1}/
assets.each do |file|
next if File.directory?(file) || file !~ regex
source = file.split('/')
source.push(source.pop.gsub(regex, '.'))
non_digested = File.join(source)
if manifests.any? {|m|
if m.is_a? Regexp
m.match non_digested
else
m.ends_with?(non_digested)
end
}
puts "** copy source: #{file}"
puts "** copy destination: #{non_digested}"
FileUtils.cp(file, non_digested)
end
end
end
end
Rake::Task['assets:precompile'].enhance do
puts "Invoke nonfingerprint_assets"
Rake::Task['app:nonfingerprint_assets'].invoke
end
This rake task is working fine on my local machine even in production environment. It creates a file in public/assets/application.js which is the copy of the same file with a digest in its name.
When I deploy this code to heroku I get the following error message which I don't understand:
-----> Preparing app for Rails asset pipeline
Running: rake assets:precompile
[deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_
locales = false to avoid this message.
Invoke nonfingerprint_assets
** copy source: /tmp/build_48b86bff-83f9-4d21-8b21-712c1baef811/public/assets/application-51d1660b66655782ab137ee98c789fdd.js
** copy destination: /tmp/build_48b86bff-83f9-4d21-8b21-712c1baef811/public/assets/application.js
rake aborted!
No such file or directory - /tmp/build_48b86bff-83f9-4d21-8b21-712c1baef811/public/assets/application.js
/tmp/build_48b86bff-83f9-4d21-8b21-712c1baef811/lib/tasks/production.rake:26:in `block (3 levels) in <top (required)>'
/tmp/build_48b86bff-83f9-4d21-8b21-712c1baef811/lib/tasks/production.rake:9:in `each'
/tmp/build_48b86bff-83f9-4d21-8b21-712c1baef811/lib/tasks/production.rake:9:in `block (2 levels) in <top (required)>'
/tmp/build_48b86bff-83f9-4d21-8b21-712c1baef811/lib/tasks/production.rake:45:in `block in <top (required)>'
Tasks: TOP => app:nonfingerprint_assets
(See full trace by running task with --trace)
Please help me to understand what's going on.
I have built a rake task --
# SET RAKE TASK NAMESPACE
namespace :db do
# RAKE TASK DESCRIPTION
desc "Fetch property information and insert it into the database"
# RAKE TASK NAME
task :insert_properties do
# REQUIRE LIBRARIES
require 'nokogiri'
require 'open-uri'
# OPEN THE XML FILE
mits_feed = File.open("app/assets/xml/mits.xml")
# OUTPUT THE XML DOCUMENT
doc = Nokogiri::XML(mits_feed)
# FIND PROPERTIES OWNED BY NORTHSTEPPE AND CYCLE THORUGH THEM
doc.xpath("//Property/PropertyID/Identification[#OrganizationName='northsteppe']").each do |property|
# GATHER EACH PROPERTY'S INFORMATION
information = {
"street_address" => property.xpath("/Address/AddressLine1/text()"),
"city" => property.xpath("/Address/City/text()"),
"zipcode" => property.xpath("/Address/PostalCode/text()"),
"short_description" => property.xpath("/Information/ShortDescription/text()"),
"long_description" => property.xpath("Information/LongDescription/text()"),
"rent" => property.xpath("/Information/Rents/StandardRent/text()"),
"application_fee" => property.xpath("/Fee/ApplicationFee/text()"),
"bedrooms" => property.xpath("/Floorplan/Room[#RoomType='Bedroom']/Count/text()"),
"bathrooms" => property.xpath("/Floorplan/Room[#RoomType='Bathroom']/Count/text()"),
"bathrooms" => property.xpath("/ILS_Unit/Availability/VacancyClass/text()")
}
# CREATE NEW PROPERTY WITH INFORMATION HASH CREATED ABOVE
Property.create!(information)
end # ENDS XPATH EACH LOOP
end # ENDS INSERT_PROPERTIES RAKE TASK
end # ENDS NAMESAPCE DECLARATION
when I run "rake db:insert_properties" this is the error I produce --
rake aborted!
uninitialized constant Property
/Users/stevejobs/Sites/nsrosu/lib/tasks/property_information.rake:39:in `block (3 levels) in <top (required)>'
/Library/Ruby/Gems/2.0.0/gems/nokogiri-1.6.1/lib/nokogiri/xml/node_set.rb:237:in `block in each'
/Library/Ruby/Gems/2.0.0/gems/nokogiri-1.6.1/lib/nokogiri/xml/node_set.rb:236:in `upto'
/Library/Ruby/Gems/2.0.0/gems/nokogiri-1.6.1/lib/nokogiri/xml/node_set.rb:236:in `each'
/Users/stevejobs/Sites/nsrosu/lib/tasks/property_information.rake:21:in `block (2 levels) in <top (required)>'
Tasks: TOP => db:insert_properties
(See full trace by running task with --trace)
I have a Property model with a table set up to accept all of these attributes, so why am I getting this error?
Your rake task needs to boot the Rails environment prior to running. That way you can access the classes.
To do this, you need to run the environment task. To make this happen, change your task definition to
task :insert_properties => :environment do