iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

0

大綱

還記得在建立rails 的 database時,我們跑過

rake db:create  # 依照目前的 RAILS_ENV 環境建立資料庫
rake db:migrate # 執行Migration動作

所以...

rake 是什麼?

Rake 是 Ruby 的任務腳本,讓我們在CLI中可以執行。提供良好的任務編寫結構,且很方便設定各個任務的相依性,或是搭配像是whenever gem 就可以排程執行任務。

Rake藉由讀取叫做Rakefile的檔案來執行任務腳本,而這些任務腳本就是所謂的task。在 Rails 環境中撰寫 Rake,請將附檔名命名為.rake,並將檔案放在 lib/tasks目錄下,例如:

lib/tasks/ironman.rake

task :ironman do
  puts '我要寫三十篇'
end

透過task這個方法定義 task_name。像是ironman就是這個task的名稱;接著使用block,並把想要執行的Ruby程式碼放在裡面

要執行這個task的話,只要在console下rake task_name,像這樣:

rake ironman
# => 我要寫三十篇

rake -T 與 desc

想知道目前有哪些 rake 可以用,只要在console下

rake -T  # rake --task 也可以,rake -T 是縮寫

有偵探精神的人一定覺得奇怪,怎麼沒有剛才建立的:ironman task?

rake -T預設只會列出有 description的task,所以如果你希望定義的task在列表中顯示的話,可以在task上方使用desc method來加入描述:

desc '30 days ironmon'
task :ironman do
  puts '我要寫三十篇'
end

再下一次rake -T


有了 (๑•̀ㅂ•́)و✧

namespace 命名空間

namespace 常用來區隔不同情況卻有相同名稱task。例如不同的情況下分別定義兩個create的task,但是當我們呼叫create的時候可能會產生不必要的麻煩,就可以透過namespace來避免這個問題。

namespace :ithelp do
  desc '30 days ironmon'
  task :ironman do
    puts '我要寫三十篇'
  end
end

在console執行時,也要加上namespace

rake ithelp:ironman
# => 我要寫三十篇

執行rake -T

可以看到多了前綴字,ithelp
也就可以理解為什麼用rake -T列出rake時,大部分的rake 名稱都有:,不然db:createtmp:create,如果都只有create這個task name,Rails 也會被你搞混。

task 依賴關係

如果 task 在執行前必須要有前置作業( prerequests ),也就是執行 task_b 前要先執行task_a,可以在task_name後面再放一個task_name,像這樣:

desc 'task_a'
task :task_a do
  puts 'task_a'
end

desc 'task_b'
task task_b: :task_a do
  puts 'task_b'
end

輸出結果:

task_a #先執行 task_a 
task_b

如果有多個前置作業要執行,也可以用矩陣的方式

desc 'task_b'
task task_b: [:task_a, :task_c]  do
  puts 'task_b'
end

那麼會以 :task_a => :task_c => :task_b 的順序執行。

environment 載入環境中的model

一般的task並沒有載入環境中的model,可以透過先執行:environment 這個 rails 預設的 task來載入 DB 環境。

desc 'Product titles'
task product_titles: :environment  do
  puts Product.pluck(:title)
end

執行後可以得到

商品一
七代目火影

如果拿掉:environment 會噴這個錯:

帶入參數給 Task

如果rake 要帶入參數,就在task_name後面給一個以Symbol為元素的矩陣,然後在 block 內就可以呼叫args這個參數集合

desc 'Example of task with parameters and prerequisites'
task :my_task, %i[first_arg second_arg] do |t, args|
  args.with_defaults(second_arg: 'Bar')    #設定second_arg的預設值為"Bar"
  puts "First argument was: #{args.first_arg}"
  puts "Second argument was: #{args.second_arg}"
end

執行這個task 時,因為有帶參數,rake_name跟參數矩陣要用括號包起來

rake "my_task[one,two]"    

輸出結果:

First argument was: one
Second argument was: two

block 內部的args其實是Rake::TaskArguments的實體,如果在task block 設中斷點byebugargs會長這樣:

#<Rake::TaskArguments second_arg: two, first_arg: one>

可以透過兩種方式args[:first_arg]args.first_arg來取第一個參數"one"

with_defaults 方法可以設定預設值

上面的my_task block內呼叫#with_defaults方法就可以 hash 形式設定特定參數預設值:

args.with_defaults(second_arg: 'Bar') 

不想在前置作業執行 rake

前面提到如果想執行其他rake,可以放在前置作業去執行,但是

不想放在前置作業執行呢?

就要使用Rake::Task['task_name'].invoke

desc 'task_b'
task task_b: [:task_a, :task_c]  do
  puts 'task_b'
  Rake::Task['ithelp:ironman'].invoke
end

輸出

task_a
task_c
task_b
我要寫三十篇
我要寫三十篇

指定執行環境

rake會預設在development的環境下執行。如果你需要指定執行環境的話,透過RAILS_ENV=your_environment的指令來指定。

rake db:schema:dump RAILS_ENV=production

最後

提醒一下,rails server 不载入 .rake 文件,所以在 rails console 或是 runtime 時,都不能執行rake。


上一篇
[Day 22] ActiveHash 內建資料
系列文
關於 Ruby on Rails,我想說的是23

尚未有邦友留言

立即登入留言