задания cron в rails 3 через rake
В этой статье, я персонально для себя, опишу метод запуска задания cron в Ruby on Rails 3 через rake. Об этом способе я узнал из комментария к статье задания cron в ROR 3, который написал Леонид Шевцов, приведя ссылку на railscasts.com.
На railscasts есть видео на английском показывающее как запускать Ruby-код, использующий все преймущества Active Records, а точнее работающий в среде вашего rails-приложения. Я же хочу просто резюмировать это видео и привести его в текстовый вид, заодно проверив все это на собственном опыте.
запись и запуск кода
Начнем с того, что если вы наберете команду $ rake -T
, то сможете увидеть список и описание всех команд rake.
Теперь подробнее. Заходим в rails_app/lib/tasks/
и создаем файл, где собственно и будет наш код – rails_app/lib/tasks/crontask.rake
.
Открываем его и пишем для начала так:
1 2 3 | task :greet do puts 'Hello world!' end |
Возвращаемся в консоль:
1 2 3 | $ rake greet (in /home/myusername/rails3/rails_app) Hello world! |
В это файл можно прописать сколь угодно много таких task’ов и каждый из них будет запускатся согласно rake <task_name>
.
цепочка заданий
Усложним пример, добавив в файл еще одна задание – :ask
:
1 2 3 4 5 6 | task :greet do puts 'Hello world!' end task :ask => :greet do puts 'How are u?!' end |
Теперь по вызову задания ask
первоначально будет запускатся цепь: greet->ask
:
1 2 3 4 | $ rake ask (in /home/myusername/rails3/rails_app) Hello world! How are u?! |
запуск в среде rails-приложения
Если попытаться использовать в задании в таком виде какие-нибудь ресурсы среды вашего приложения, а иначе говоря обращаться к БД через Active Records, то ничего не получится.
Например:
1 2 3 4 | task :first_nah do product=Product.first puts product.title end |
1 2 3 4 | $ rake first_nah (in /home/myusername/rails3/rails_app) rake aborted! uninitialized constant Product |
Чтобы все было четко делаем по логике ‘запуска цепочки’ т.е. если нам нужна среда – запустим среду:
1 2 3 4 | task :nah_first => :environment do product=Product.first puts product.title end |
пространство имен
Допустим есть несколько заданий имеющих непосредственное отношение друг к другу, быть может они даже имеют схожие имена.
1 2 3 4 5 6 7 8 9 | task :nah_first => :environment do product=Product.first puts product.title end task :nah_last => :environment do product=Product.last puts product.title end |
В таком случае их можно запихнуть в одну группу, пространство имен.
1 2 3 4 5 6 7 8 9 10 | namespace :nah do task :first => :environment do product=Product.first puts product.title end task :last => :environment do product=Product.last puts product.title end end |
В консоли:
1 2 3 4 5 6 | $ rake nah:last (in /home/myusername/rails3/rails_app) Last_product $ rake nah:first (in /home/myusername/rails3/rails_app) First_product |
группы заданий
Если не хотите напрягаться и запускать каждое задание новой командой, можно объединить задания в группу.
1 2 3 4 | namespace :nah do #код заданий :first и :last task :all => [:first,:last] end |
В консоли:
1 2 3 4 | $ rake nah:all (in /home/myusername/rails3/rails_app) First_product Last_product |
методы в rake
Пусть в заданиях повторяется один и тот же код, допустим это запрос БД. В таком случае целесообразно прописать его один раз в метод.
1 2 3 4 5 6 7 8 9 10 11 12 | namespace :shop do task :product => :environment do product=Product.where('id > ?',20).first puts product.title end task :categor => :environment do cat=Categor.where('id > ?',20).first puts cat.title end task :all => [:product,:categor] end |
В таком случае лучше сделать метод, который будет выполнять этот запрос.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | namespace :shop do task :product => :environment do puts echo(Product).title end task :categor => :environment do puts echo(Categor).title end task :all => [:product,:categor] def echo (model_class) model_class.where('id > ?',20).first end end |
описание заданий
Чтобы не путаться в заданиях, их можно кратко описать.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | namespace :shop do desc 'Show first product, which id > 20' task :product => :environment do puts echo(Product).title end desc 'Show first categor, which id > 20' task :categor => :environment do puts echo(Categor).title end desc 'Show first product and category' task :all => [:product,:categor] def echo (model_class) model_class.where('id > ?',20).first end end |
Теперь в консоли можно увидеть справку по командам.
1 2 3 4 5 6 7 | $ rake -T (in /home/myusername/rails3/rails_app) rake about # List versions of all Rails... ... rake shop:all # Show first product and categor rake shop:categor # Show first categor, which id > 20 rake shop:product # Show first product, which id > 20 |
не смотря на все преймущества rake-метода, здесь все также присутствует ошибка с кодировками:
rake aborted!
"\x8B" from ASCII-8BIT to UTF-8
...
/usr/local/lib/ruby/1.9.1/rake.rb:634:in `call'
/usr/local/lib/ruby/1.9.1/rake.rb:634:in `block in execute'
/usr/local/lib/ruby/1.9.1/rake.rb:629:in `each'
/usr/local/lib/ruby/1.9.1/rake.rb:629:in `execute'
/usr/local/lib/ruby/1.9.1/rake.rb:595:in `block in invoke_with_call_chain'
/usr/local/lib/ruby/1.9.1/monitor.rb:201:in `mon_synchronize'
/usr/local/lib/ruby/1.9.1/rake.rb:588:in `invoke_with_call_chain'
/usr/local/lib/ruby/1.9.1/rake.rb:581:in `invoke'
/usr/local/lib/ruby/1.9.1/rake.rb:2041:in `invoke_task'
/usr/local/lib/ruby/1.9.1/rake.rb:2019:in `block (2 levels) in top_level'
/usr/local/lib/ruby/1.9.1/rake.rb:2019:in `each'
/usr/local/lib/ruby/1.9.1/rake.rb:2019:in `block in top_level'
/usr/local/lib/ruby/1.9.1/rake.rb:2058:in `standard_exception_handling'
/usr/local/lib/ruby/1.9.1/rake.rb:2013:in `top_level'
/usr/local/lib/ruby/1.9.1/rake.rb:1992:in `run'
Решить ее предлагаю также как и в статье задания cron в ROR 3 через модели.
если такая же ошибка с кодировками появляется в контроллере:
invalid multibyte char (US-ASCII)
то решается она путем добавления в начало файла строки:
# coding: utf-8
Спасибо. Все предельно коротко и ясно.