How to invoke ActiveRecord statement in a bundle subshell? - ruby-on-rails

I have a rake task that invokes a bundle subshell and uses ActiveRecord 3.x/4.x (depending on what is passed in args):
task :some_task do |t, args|
Bundler.with_clean_env do
ENV['BUNDLE_GEMFILE'] = File.expand_path(args[:gemfile] || (File.dirname(__FILE__) + '/test/config/gemfiles/Gemfile.rails-3.2.x'))
ENV['DB'] = args[:db] || 'mysql2'
system "bundle install"
# ActiveRecord::Base.configurations = YAML.load(ERB.new(File.read(File.dirname(__FILE__) + '/config/database.yml')).result)
end
end
I want to be able to set ActiveRecord::Base.configurations to a particular configuration in database.yml as above. I thought to try something like after the bundle install statement:
system 'bundle exec ruby -e ActiveRecord::Tasks::DatabaseTasks.some_method_which_always returns_an_error"'
Usually I get either "uninitialized constant ActiveRecord (NameError)" or syntax error when I try "require %(active_record); && ActiveRecord::Tasks::Databas...",
1) Is it possible to initialize ActiveRecord::Base.configurations in a particular bundle subshell independent of Rails?
2) If yes to #1, how to do that?
The whole point is to be able to use different version of ActiveRecord via a clean "bundle install" called by the Ruby Kernel#system command

Related

rake db:dump fails when specifying an environment

I am using the gem yaml_db to generate a db dump.
The regular invocation with
rake db:dump
works as intended. However when I specify another environment like
RAILS_ENV=development-mysql rake db:dump
the command fails with:
Don't know how to build task 'db:dump'
Thanks for your ideas.
Maybe the yaml_db gem is in the development group of your Gemfile. This results in the fact that if you run RAILS_ENV=development-mysql rake db:dump Bundler loads only the general gems and not the gems from development-mysql.
You need to add yaml_db to a group named development-mysql.
Without using gem, you can dump your database with (RAILS_ENV=production) rake db:dump.
In your lib/tasks/db.rake
namespace :db do
desc "Dumps the database to backups"
task :dump => :environment do
cmd = nil
with_config do |app, host, db, user|
cmd = "db_password pg_dump -h host -d #{db} -U db_username > /path/to/file/#{db}.psql"
end
puts cmd
exec cmd
end
private
def with_config
yield Rails.application.class.parent_name.underscore,
ActiveRecord::Base.connection_config[:host],
ActiveRecord::Base.connection_config[:database],
ActiveRecord::Base.connection_config[:username]
end
end
Here is the source.

How can I run a rake task via cron?

I have and rails application and a rake task which I'm going to execute by cron around once in an hour. But the thing is that the task uses rails environment and some classes of my rails application. If I run it as ruby script, I'll have to include all the dependencies it uses and I think it's not possible to do it correctly and in a simple way. So I'll have to run it as a rake task because it'll preserve all the dependencies, right? Then how can I run a rake task from cron?
Note that I prefer not to use any third-party solution when there's no necessity, in this case I don't want to use the gem whenever or the like.
You can add to your crontab something like
0 * * * * /bin/bash -l -c 'cd /path/to/your/project && bundle exec rake foo:bar >> log/cron.log 2>&1'
This will run foo:bar task every hour and write stdout and stderr to log/cron.log.
Please notice bundle exec before rake command.
Using bundler ensure you that task will fetch correct environment.
To specify RAILS_ENV you can do
... && RAILS_ENV=production bundle exec rake foo:bar
Use whenever to simplify your life https://github.com/javan/whenever ;)
Here's an example of a rake task:
task :foo => :environment do
puts "Running rake task in environment: #{Rails.env}"
# can access Models here or whatever
end
Note that the => :environment part is optional, but it what makes your Rails environment to the task block.
You can put rake run_my_task in your cron job.
You may need to use something like cd /home/$USER/my_rails app && rake run_my_task to ensure that the cron runs the task from the Rails root directory.

Set ruby path for run model function using whenever gem in rails

In my rails application, i want to run model function using whenever gem.
My schedule.rb file like,
set :environment, 'development'
set :output, "#{path}/log/cron.log"
set :job_template, "bash -l -c ':job'"
job_type :runner, "cd :path && bin/rails runner -e :environment ':task' :output"
every 2.minutes do
runner "Book.jobrun"
end
every 2.minutes do
command "echo 'rink4'"
end
And book.rb model like,
self.jobrun
Rails.logger.info "cronjob is running"
end
But when i run cronjob, in cron.log file showing,
bin/rails:3: undefined method `require_relative' for main:Object (NoMethodError)
How i need to set ruby path or rails path?
Try running which ruby from cron. Is it as you expect? If not, cron is likly defaulting to system Ruby which in your case is probably version 1.8.7 and doesn't have the require_relative function.
Check which ruby executble you're using with which ruby. And use this in the shebang at the top of your bin/rails. for instance
bin/rails
#!/Users/<username>/.rvm/rubies/ruby-2.2.4/bin/ruby.

Cron + Rake task trying to invoke sqlite3 (only Dev/Test) in Staging (rake works from shell)

In my Rails 3.2 app I have a custom rake task that I am trying to run every day at 5pm with a cron job. Right now I am running it on our site's Staging server. The cron job is setup correctly but according to the e-mail output from the cron daemon the rake is being aborted because it's trying to invoke sqlite3.
Here is my cron job:
#crontab
0 17 * * * cd /u/apps/my_app/current && /usr/local/bin/rake my_task
I have reserved sqlite3 for development and test, like so:
#Gemfile
group :development, :test do
gem 'factory_girl_rails'
gem 'letter_opener'
gem 'rspec-rails'
gem 'sqlite3'
gem 'thin'
gem 'pry-rails'
end
I also have set my rake task to load the proper environment like so:
#mytask.rake
task :my_task => :environment do
# my task
end
This is the error I'm getting in the e-mail from crond:
rake aborted!
Please install the sqlite3 adapter: `gem install activerecord-sqlite3-adapter` (sqlite3 is not part of the bundle. Add it to Gemfile.)
If I run the rake tasks directly from the shell I don't get an error. It would seem that this works because of the following line in ~/.bashrc:
alias rake='RAILS_ENV=staging rake'
This, however, doesn't seem to have any effect on the task when run from the cron job. I've tried adding export RAILS_ENV=staging to the .bashrc file as recommended here but it didn't help.
The one thing I've found that works is writing the cron job like this:
#crontab
0 17 * * * cd /u/apps/my_app/current && /usr/local/bin/rake my_task RAILS_ENV=staging
...with the env declaration directly in the cron command. This doesn't seem very elegant but it's okay for now. Is there a better way to go about this?
Υou can set the environment variables in crontab (not in Arch or RedHat though...)
try setting your crontab as follows
#crontab
RAILS_ENV=staging
0 17 * * * cd /u/apps/my_app/current && /usr/local/bin/rake my_task

Missing required gems when execute cron created by whenever gem in production environment

I've ruby on rails application running in production, this apps have STOCK model and it should be updated every 1 minute.
For updating this model i create simple rake task db:populate:stocks, when it contain only two operation :
truncate the STOCK model
fill STOCK model with latest data fetch from webservice
this rake task should be execute every 1 minute, for this purpose i use whenever gem. Here my schedule.rb :
env :PATH, ENV['PATH']
set :job_template, nil
set :output, {:standard => '/home/admin/shared/log/cron.log', :error => '/home/admin/shared/log/cron-error.log'}
job_type :rake, "cd :path && rake :task RAILS_ENV=:environment --trace :output"
every 1.minute do
rake "db:populate:stocks"
end
In production i'm using rvm running ruby 1.9.2-p180, rails 3.1.0 and capistrano, here my capistrano task for update cron tab :
after "deploy:update_code" do
run "cd #{release_path} && whenever --clear-crontab RAILS_ENV=production"
run "cd #{release_path} && whenever --update-crontab RAILS_ENV=production"
end
And my schedule.rb create cron task like :
# Begin Whenever generated tasks for: RAILS_ENV=production
PATH=/home/admin/.rvm//gems/ruby-1.9.2-p180#admin/bin:/home/admin/.rvm//gems/ruby-1.9.2-p180#global/bin:/home/admin/.rvm//rubies/ruby-1.9.2-p180/bin:/home/admin/.rvm//bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
* * * * * cd /home/admin/releases/20120904103658 && RAILS_ENV=production rake db:populate:stocks --trace >> /home/admin/shared/log/cron.log 2>> /home/admin/shared/log/cron-error.log
THE PROBLEM is the cron task failed to execute the rake task, from cron-error.log :
/home/admin/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/site_ruby/1.9.1/rubygems.rb:314:in `bin_path': can't find gem rake ([">= 0"]) with executable rake (Gem::GemNotFoundException)
from /home/admin/.rvm//gems/ruby-1.9.2-p180#admin/bin/rake:19:in `<main>'
What i'm missing here, why the cron job failed to load my env ? Is there any problem with my schedule.rb ?
Make sure your RVM defaults to the correct ruby version where the gems are.
Then try to use bundle exec rake ...
by doing so it will explicitly invoke whatever the gems in the bundle (assuming you are using RVM)
I have similar problem and I fix with
rvm cron setup
in server. This add rvm env variables (PATH, GEM_HOME,GEM_PATH...) to my cronjob.
I have to delete the set command
env :PATH, ENV['PATH']
modifying PATH is not enough, check rvm help cron - there are few options that will help manage rvm in crontab.

Resources