Rake task in Rails

Khái niệm

Rake là công cụ để quản lí các task trong rails, với mục đích gom nhóm các đoạn code ruby thường xuyên được sử dụng vào một task chung để sử dụng lại nhiều lần. Vd như các câu lệnh thường được chúng ta sử dụng nhiều như rake db:migrate, rake db:create, rake db:seed, rake assets:precompile.. Các câu lệnh này sẽ chạy các code ruby ở bên trong các Rakefile với namespace tương ứng. Rails sẽ tự động lấy tất cả các rake file ở trong đường dẫn lib/tasks và gom chúng vào danh sách các rake file hiện có trong rails app của chúng ta, và bên cạnh các rake task được định nghĩa sẵn của rails, chúng ta hoàn toàn có thể tùy ý tạo ra các rake task của riêng mình.

Tạo 1 Rakefile đơn giản

Để định nghĩa 1 rake file, chúng ta có thể dùng cú pháp:

rails g task [namespace] [task]

Sau khi thực hiện câu lệnh trên, trong thư mục lib/tasks sẽ xuất hiện 1 file .rake với tên file trùng với tên task. Hoặc chúng ta có thể tạo file rake thủ công ở trong thư mục lib/tasks, mình thường dùng cách này hơn. Vd như chúng ta có Rakefile là user.rake và định nghĩa 1 task là say_hi:

namespace :user do
  task :say_hi do
    puts "hi"
  end
end

Chạy thử Rakefile: rake user:say_hi.

Tùy chọn dependency :environment

Khi định nghĩa 1 task, chúng ta cần thêm định nghĩa dependency :environment để load Rails Enviroment cần thiết để có thể truy cập vào các model,.. Ở đây nếu như chúng ta chỉ định nghĩa các câu lệnh đơn giản như puts "hi" thì sẽ không cần định nghĩa dependency :environment, nhưng khi chúng ta cần đụng chạm đến model User, vd như User.find(1) hay User.create, thì sẽ phải định nghĩa thêm:

namespace :user do
  task :say_hi do
    puts "hi"
  end
  task create: :environment do
    User.create name: "A"
  end
end

Dùng desc để thêm mô tả

Khi chúng ta định nghĩa nhiều tasks khác nhau trong cùng namespace, để rõ ràng hơn thì ta có thể thêm một vài mô tả trong file rake thông qua desc:

namespace :user do
desc "this is user Rakefile"
...

Check Rake files list và default task

Xem toàn bộ danh sách rake hiện có trong app: rake -T The default task: task mặc định khi chạy rake, khai báo qua cú pháp task default: [:name]

Invoking tasks

Có 1 kỹ thuật rất hay được sử dụng là Invoking task. Dùng để gọi task này ở trong task khác với cú pháp: Rake::Task["task_name"].invoke Vd như ta định nghĩa 1 rake task để mỗi khi gọi đến thì sẽ reset lại db và seeding lại dữ liệu, điều này tương đương với việc gọi các task: db:drop, db:create , db:migrate..

namespace :db do
  desc "remake database data"
  task remake_data: :environment do
    %w[db:drop db:create db:migrate].each do |task|
      Rake::Task[task].invoke
    end
    puts "You will be prompted to create data for project."
    100.times do |n|
      name = Faker::Name.name
      email = "email-#{n+1}@framgia.com"
      password = "password"
      User.create! name:  name, email: email, password: password,
        password_confirmation: password
    end
    puts "The data was created successfully."
  end
end

Và sau đó chúng ta chỉ việc gọi đến task đó khi cần remake lại db với lệnh: rake db:remake_data

Task Overriding

Rails cũng cho phép chúng ta định nghĩa lại 1 task mặc định, chẳng hạn như db:migrate. Lưu ý ở đây là task mới mà chúng ta định nghĩa lại sẽ không override lại hoàn toàn mà chỉ đơn giản là thêm các dòng lệnh phía sau task gốc đó. Để định nghĩa lại 1 task, cần dùng cùng name:

namespace :db do
  task migrate: :environment do
    puts "I'm overriding db:migrate task."
  end
end

Passing Argument

Chúng ta cũng có thể truyền tham số hoặc sử dụng biến ENV trong Rake task. Cách thứ nhất là chúng ta có thể truyến thẳng tham số vào task, vd:

namespace :calculate do
  task :add, [:num1, :num] do |t, args|
    puts args[:num1].to_i + args[:num].to_i
  end
end

rồi gọi: rake calculate:add[1,2], kết quả in ra màn hình sẽ là 3. Tuy nhiên với cách truyền trực tiếp như vậy thì với những người dùng zsh shell sẽ gặp lỗi ở công đoạn gọi rake:

zsh: no matches found: calculate:add[1,2]

Nguyên nhân là vì chúng ta chưa "escape" dấu ngoặc vuông [, cách xử lí là viết lại lệnh gọi rake như sau: rake calculate:add\[1,2\], kết quả sẽ in ra ngon lành. Nhìn không được đẹp mắt lắm, may mà chúng ta còn 1 số cách khác trọn vẹn cả 2, chẳng hạn như sử dụng biến môi trường ENV:

namespace :calculate do
  task :add do
    puts ENV['NUM1'].to_i + ENV['NUM2'].to_i
  end
end

rồi gọi: rake calculate:add NUM1=1 NUM2=2 Tuy nhiên ở đây ngoại trừ việc không cần thêm kí tự escape rắc rối như cách đầu, cú pháp được giữ nguyên định dạng, thì đối với trường hợp này việc set giá trị cho các biến ENV thường là không cần thiết. Còn 1 vài cách khác để truyền biến vào trong task, các bạn có thể tham khảo thêm ở đây.

Lời kết

Mình xin đóng góp chút kiến thức nhỏ về Rake task Rails để chia sẻ với mọi người. Bài viết còn nhiều thiếu sót, mong được mọi người góp ý, cảm ơn vì đã dành thời gian đọc bài viết của mình.