My simple rake task, stored in lib/tasks/items_spider.rake runs just fine in development. All it does is call spider! on the Item model.
namespace :items do
desc "Spider the web for data, hoorah"
task :spider => :environment do
Item.spider!
end
end
I have the :environment task as a dependency, so everything works just fine. However, when I add RAILS_ENV=production, I hit errors, both on my local server and the production server:
$ rake items:spider RAILS_ENV=production --trace
(in /home/matchu/Websites/my-rails-app)
** Invoke items:spider (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute items:spider
rake aborted!
uninitialized constant Object::Item
/home/matchu/.rvm/gems/ruby-1.9.2-preview3#rails3/gems/rake-0.8.7/lib/rake.rb:2503:in `const_missing'
/home/matchu/.rvm/gems/ruby-1.9.2-preview3#rails3/gems/rspec-core-2.0.0.beta.22/lib/rspec/core/backward_compatibility.rb:20:in `const_missing'
/home/matchu/.rvm/gems/ruby-1.9.2-preview3#rails3/gems/rspec-expectations-2.0.0.beta.22/lib/rspec/expectations/backward_compatibility.rb:6:in `const_missing'
/home/matchu/Websites/openneo-impress-items/lib/tasks/items_spider.rake:4:in `block (2 levels) in <top (required)>'
/home/matchu/.rvm/gems/ruby-1.9.2-preview3#rails3/gems/rake-0.8.7/lib/rake.rb:636:in `call'
[...trace of how rake gets to my task...]
This just seems odd to me. Apparently the models have not been loaded correctly. I'm on Rails 3.0.3, though development on this app started back when Rails 3 was in beta. How can I go about debugging this issue? Thanks!
Contrary to running your application in production, a Rake task does not eager load your entire code base. You can see it in the source:
module Rails
class Application
module Finisher
# ...
initializer :eager_load! do
if config.cache_classes && !$rails_rake_task
ActiveSupport.run_load_hooks(:before_eager_load, self)
eager_load!
end
end
# ...
end
end
end
So only if $rails_rake_task is false, will the application be eager-loaded in production. And $rails_rake_task is set to true in the :environment Rake task.
The easiest workaround is to simply require the model that you need. However, if you really need all of your application to be loaded in the Rake task, it is quite simple to load it:
Rails.application.eager_load!
The reason all of this work in development is because Rails autoloads your models in development mode. This also works from within a Rake task.
In your environment/production.rb, you should add the following:
config.dependency_loading = true if $rails_rake_task
It solved the problem for me.
(Note: this should be added AFTER the config.threadsafe! call)
The same thing happens to me in Rails 6.0.3.2.
I was trying to configure the rake file task :foo do ... end. Instead it should've been task foo: :environment do ... end.
Just found another one: I was developing on windows, deploying to Heroku. The web app and rails console worked fine, but rake tasks and even direct require could not load the model. Turned out I had absentmindedly created the model file as Model.rb instead of model.rb - system dependent case sensitivity.
Related
I am upgrading to rails 7.0.3.1 from rails 6.1.6.1. Whenever I run a rake task there is an exception generated. For example with this simple rake task
namespace :tests do
task temp: :environment do
puts "Environment is #{Rails.env}"
end
end
if I run rake tests:temp then I see the following
Precompiling assets for local
precompile asset_host is
rake aborted!
KeyError: key not found: "APPLICATION_HOST"
/Users/myname/myapp/config/environments/production.rb:8:in `fetch'
...
Tasks: TOP => environment
(See full trace by running task with --trace)
[master c970ac9] Add precompiled assets for local
2 files changed, 1593 insertions(+), 1840 deletions(-)
...
Environment is development
I can provide the full trace if requested. Note that after the exception, the rake test does work successfully. Also the code is making a git commit to the effect Add precompiled assets for local. The environment variable APPLICATION_HOST is not set in the development environment, because it is only needed in production.
I was not seeing this problem in rails 6. What is causing this?
It turns out that I have a method defined in a Mixin which looks like this
def precompile_assets(target: 'local)
puts "Precompiling assets for #{target}"
...
system("RAILS_ENV=production RAILS_HOST_PATH=#{asset_host} rake assets:precompile")
end
This was only meant to be used in rake tasks used for deployment. It looks like somewhere in Rails 7 there is another method with the same name, which is being overwritten. The quick solution is rename the method so it does not clash. The longer solution is refactor so as it is not a Mixin.
I guess all those articles about the dangers of Mixins were right.
So, I have actually two issues, but I bet they are connected to each other.
I have to call a rake task on a legacy app (also the task is legacy) but run into "Don't know how to build task 'environment'" and "uninitilized constant" errors. We're working in Rails 5.2 with ruby 2.5.1.
The rake file is in lib/tasks/migrations/models.build_stuff.rb
It looks like this:
include ActionView::Helpers
namespace :migrations do
namespace :build_stuff do
task build_first_things: :environment do
puts 'Starting building first things'
FirstThings.each { |thing| thing.build! }
puts 'Done!'
end
task build_second_things: :environment do
puts 'Starting building second things'
SecondThings.each { |thing| thing.build! }
puts 'Done!'
end
end
end
So, I call the first task with:
rake -f ./lib/tasks/migrations/models/build_first_things.rake migrations:build_stuff:build_first_things
Here I get the following error:
rake aborted!
NameError: uninitialized constant ActionView
I know, in my example there is not even an ActionView helper used, in the real file, there is.
If, just for testing reasons, I delete the line with include ActionView::Helpers another error is raised:
rake aborted!
Don't know how to build task 'environment' (See the list of available tasks with `rake --tasks`)
I don't want to call a task 'environment', just need to load the app and access the database.
Does anyone know, why either (or) both things happen?
Thank you very very much :)
*** Solution ***
It worked when calling bin/railsor bundle exec rakeinstead of simply rake.
Here is my console:
ilya#SamsungRV-509:~/MyProjects/easy_learning$ rake db:migrate RAILS_ENV=test
== SetPasswordToAdministrator: migrating =====================================
DEPRECATION WARNING: This dynamic method is deprecated. Please use e.g. Post.find_or_create_by(name: 'foo') instead. (called from up at /home/ilya/MyProjects/easy_learning/db/migrate/20131210185519_set_password_to_administrator.rb:3)
[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.
rake aborted!
An error has occurred, all later migrations canceled:
undefined method `mobile' for #<User:0xba972894>/home/ilya/MyProjects/easy_learning/db/migrate/20131210185519_set_password_to_administrator.rb:3:in `up'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
Here is my file:
class SetPasswordToAdministrator < ActiveRecord::Migration
def up
admin = ::User.find_or_create_by_email_and_name("admin#email.com", "Admin")
admin.password = admin.password_confirmation = "easylearning"
admin.role = "Administrator"
admin.save!
end
end
You need to run two rake tasks (or ensure they've been run) first to get going with Rspec as it relates to your DB:
rake db:create:all
This ensures that your test DB was created.
rake db:migrate db:test:clone
This will ensure that your test database is both up-to-date and ready for your specs to run.
Over the last year as I've worked to get better about T/BDD and Rspec in particular, I no longer even run rake db:migrate alone. I always run rake db:migrate db:test:clone now!
If you are running Rails 4.1+, RSpec has a feature that keeps your test database synchronised with development. This from the RSpec website:
To take advantage of this add the following to the top of the rails_helper file after Rails has been required:
ActiveRecord::Migration.maintain_test_schema!
Behaviour in Rails 4.0 is slightly different. Here is the page for more information:
https://www.relishapp.com/rspec/rspec-rails/docs/upgrade#pending-migration-checks
I have an app that I have been in happily developing for some time, and haven't had any trouble seeding the production database with my seed file until recently, as I have been attempting to get capistrano deployment working, which spawned an upgrade and gem dependency exercise;-first I blamed capistrano but this behavior happens locally.
So if I reset and seed with:
RAILS_ENV=production rake db:reset
and I end up with tables being undefined that the seed file is attempting to load: e.g:
...tables being built:
.
.
.
-- initialize_schema_migrations_table()
-> 0.0037s
-- assume_migrated_upto_version(20140117153600, ["/Users/jaytho/Projects/1.1.1-a1.dev.merge_test/db/migrate"])
-> 0.0020s
BankCards
rake aborted!
uninitialized constant BankCard
/Users/jaytho/Projects/1.1.1-a1.dev.merge_test/db/seeds.rb:7:in block (2 levels) in <top (required)>'
/Users/jaytho/Projects/1.1.1-a1.dev.merge_test/db/seeds.rb:6:inblock in '
/Users/jaytho/Projects/1.1.1-a1.dev.merge_test/db/seeds.rb:4:in <top (required)>'
/usr/local/rvm/gems/ruby-1.9.3-p448#global/gems/railties-3.2.16/lib/rails/engine.rb:525:inload'
/usr/local/rvm/gems/ruby-1.9.3-p448#global/gems/railties-3.2.16/lib/rails/engine.rb:525:in load_seed'
/usr/local/rvm/gems/ruby-1.9.3-p448#global/gems/activerecord-3.2.16/lib/active_record/railties/databases.rake:347:inblock (2 levels) in '
/usr/local/rvm/gems/ruby-1.9.3-p448#global/gems/activerecord-3.2.16/lib/active_record/railties/databases.rake:290:in `block (2 levels) in '
Tasks: TOP => db:setup => db:seed
(See full trace by running task with –trace)
of which BankCard is the first table seeds.rb is attempting to populate. Comment out BankCard and it just goes to the next table.
The db:reset command works perfectly with in the other environments:
RAILS_ENV=development rake db:reset
and
RAILS_ENV=test rake db:reset
a downgrade to 3.2.15 did not help. I also attempted many permutations like:
bundle exec rake db:reset RAILS_ENV=production
RAILS_ENV=production bundle exec rake db:drop db:create db:migrate db:seed
and I even wiped all my migrations and tried just from the schema thinking that a mangled migration silently causing an issue:
RAILS_ENV=production bundle exec rake db:schema:load db:seed
without any luck- exact same answer.
I also attempted to extract the seed.rb routines into a separate rake task- same result.
The brain twister for me is that if I call the seeds.rb from the console:
'echo load “db/seeds.rb”' | RAILS_ENV=production rails c
she loads without any issues. It works from the console.
I attempted to get into databases.rake and try and recreate the environment there to duplicate the environment into my own rakefile; however, since calls into databases.rake exhibit the same problem, I am pretty much stuck between a rock and a hard place.
What can I be doing wrong to pollute only the production environment? How can I debug this?
Thanks in advance. Beer is on me if you ever are in Dallas.
After some insomnia and some more varied google searches I stumbled on this website: http://community.activestate.com/node/9065 and
Rails 3.2.11 asset precompile fails if threadsafe! enabled where they give clues that threadsafe is important.
Sure enough; if I comment out the threadsafe line in config/environments/production.rb:
# Enable threaded mode
# config.threadsafe!
My rake db:seed tasks work in production.
the solutions in those articles, for some reason didn't work. I ended up doing this to fix it in config/environments/production.rb
# Enable threaded mode
config.threadsafe! unless $rails_rake_task
I hope this helps somebody else out who is upgrading.
I've written a rake task to run a few other rake tasks via system (so as to bind ActiveRecord to different databases, among other things). It works fine on my OS X box, but fails on our production Linux boxes with a load error. The tasks trivially boil down to:
namespace :jobs do
task :foo => :environment do
system "rake jobs:bar"
end
task :bar => :environment do
puts "foobar"
end
and the traced output is:
-bash-3.2$ rake jobs:foo --trace
(in /the/path)
** Invoke jobs:foo (first_time)
** Invoke environment (first_time)
** Execute environment
** Erubis 2.6.6
** Execute jobs:foo
/usr/bin/rake:19:in `load': no such file to load -- rake (LoadError)
from /usr/bin/rake:19
I dumped a puts $: into /usr/bin/rake and have discovered something interesting. The primary job has a load path containing both of these paths:
/usr/lib/ruby/gems/1.8/gems/rake-0.8.7/bin
/usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib
while the secondary job has a load path containing only:
/usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib
which probably explains the load error, but not the reason for it. Any ideas?
Check to make sure your install has set up the required environment variables correctly.
http://docs.rubygems.org/read/chapter/3
The same problem occurred for me when using "export RUBYOPT=RUBYGEM" instead of "export RUBYOPT=RUBYGEMS". Ahh the difference a single character can make.
If you are really trying to invoke a rake task from another rake task. Why not do this? "Rake::Task['jobs:bar'].invoke". You can even do it in a loop, for instance an Array#each that changes ENV vars, etc. I've done this in tasks before.
Though, if your example was contrived and your not really calling one task but just asking why the sub shell has different PATH setting, that I do not know. Perhaps if it's hard, then it's a hint that it should be done another way.