Why does a Rake task in a loop execute only once?
I have rails application that connects to multiple databases. I wrote custom rake task that looks like this:
task :migrate_accounts_schema => [:environment] do |t|
users = User.find :all, :conditions => ["state = 2"], :order => "id asc"
users.each do |user|
if user.state == 2
ActiveRecord::Base.establish_connection(
:adapter => "postgresql",
:host => user.database_host,
:port => user.database_port,
:username => user.subdomain,
:password => "#{user.database_password}",
:database => user.database_name
)
Rake::Task["db:migrate"].invoke
end
end
end
开发者_StackOverflow社区
The problem is that task executes db:migrate only for users[0] user (first user in collection) and there is no errors, just stoppes silently...
Here's output from rake --trace
** Invoke app:migrate_accounts_schema (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute app:migrate_accounts_schema
** Invoke db:migrate (first_time)
** Invoke environment
** Execute db:migrate
** Invoke db:schema:dump (first_time)
** Invoke environment
** Execute db:schema:dump
** Invoke db:migrate
I have no idea why the rest of users don't get migrated.
I found answer in the Rake source:
http://rake.rubyforge.org/classes/Rake/Task.html#M000115
It says that you have to
Reenable the task, allowing its tasks to be executed if the task is invoked again.
e.g. I used this recently on my project this way:
# db/seed.rb
Rake::Task['catalog:destroy'].invoke
files = Dir.glob("private/catalog/*").sort
files.each do |file|
next unless File.extname(file) == '.xlsx'
puts file.split('/').last
Rake::Task['catalog:upload'].invoke(file)
Rake::Task['catalog:upload'].reenable
puts
end
So I run rake catalog:upload[some_file] every loop.
Hope this helps. Also see https://stackoverflow.com/a/1290119/3082929
I forgot the exact internals but the way Rake works is that invoke
will only execute each task if it needs to (in other words once).
Try calling execute on subsequent calls:
Rake::Task["db:migrate"].execute
The first time through the loop you'll need invoke
as it invokes the prerequisites first.
精彩评论