Rake và ứng dụng thực tế
Bài đăng này đã không được cập nhật trong 5 năm
Rake là gì?
Rake (viết tắt của Ruby Make) là một task runner
phổ biến được viết bằng Ruby
, 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.
Vậy task là gì? Task ở đây có thể là những tác vụ như:
- Tạo backup database
- Cleanup database
- Chạy test
- ...
Rake dùng Rakefile
và các file có đuôi .rake
để định nghĩa một tập các task.
Rake trong Rails
Khi dùng Rails, ta đã quen với các câu lệnh như: rake routes
, rake db:migrate
, rake db:seed
... Thực chất đó là những Rake task đã được định nghĩa sẵn trong Rails nên ta chỉ việc gọi ra dùng thôi :v
Trong Rails, Rake được dùng để định nghĩa các task ở cấp độ quản lý chung. Để xem các task được định nghĩa sẵn và mô tả của chúng, ta chạy lệnh:
rake -T
Ta sẽ có kết quả sau đây:
Lưu ý: Từ Rails 5.0 trở đi, bạn có thể dùng
rails
thay chorake
để chạy các task trong Rails. Do vậy ta có thể viếtrails db:migrate
thay vìrake db:migrate
Ngoài những task mặc định được Rails định nghĩa, ta cũng override những task mặc định hoặc tạo các task mới để phục vụ mục đích riêng. Chúng ta cùng tìm hiểu cách dùng nhé :v
Cách dùng Rake
Tạo Rake task đơn giản:
Bạn có thể tạo file .rake
trong thư mục lib/tasks
hoặc chạy lệnh sau để tạo task:
rails g task [namespace] [task]
Ví dụ, ta tạo 1 task như sau:
Lệnh này sẽ tạo 1 file show.rake
trong lib/tasks
, ta thêm vào file như sau:
namespace :show do
desc "TODO"
task hello: do
puts "Hello World"
end
end
Ta chạy thử task vừa tạo: rails show:hello
. Kết quả console sẽ in ra "Hello world" thôi :v Dễ hiểu mà
Sử dụng namespace
Vì các task có thể trùng tên nhau và cũng để gom nhóm tiện cho việc quản lý nên Rake đã tạo ra namespace
Ví dụ:
namespace :backup do
task :create do
# ...
end
task :list do
# ...
end
task :restore do
# ...
end
end
Để chạy task, ta sử dụng:
rails [namespace]:[task]
Dependent Tasks
Rake cho phép bạn chạy 1 danh sách task trước khi chạy task hiện tại
task create_examples: :load_database do
# ...
end
Ví dụ trên: load_database
sẽ được chạy trước khi ta chạy create_examples
Bạn cũng có thể truyền vào một danh sách các Dependent Tasks dưới dạng mảng các String hoặc Symbol.
Các tasks này sẽ được thực hiện tuần tự theo đúng thứ tự trong mảng truyền vào.
Dependency :environment
Khi tạo task cần thao tác với model để thực hiện truy vấn database,.. Bạn cần chạy task environment
trước để load code của rails app ra trước khi chạy task:
namespace :user do
task create: :environment do
User.create name: "Hau Nguyen"
end
end
Chạy task trong task
Rake cho phép gọi task trong 1 task khác với execute
hoặc invoke
namespace :show do
desc "Hello"
task :hello do
puts "Hello World"
end
desc "Task 1"
task task1: :hello do
puts "Task 1"
end
desc "Task 2"
task :task2 do
puts "Task 2"
Rake::Task["show:task1"].execute
# OR
Rake::Task["show:task1"].invoke
end
end
Sự khác nhau giữa execute
và invoke
:
execute
: chạy task mà KHÔNG chạy các Dependent Task của nóinvoke
: chạy task và các Dependent Task của nó
Override Task mặc định
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 ý: 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 tên, cùng namespace:
namespace :db do
task migrate: :environment do
puts "Hello, I override db:migrate task."
end
end
Truyền tham số hoặc biến ENV
Tham số:
namespace :calculate do
task :add, [:num1, :num2] do |_, args|
puts args[:num1].to_i + args[:num2].to_i
end
end
Chạy thử task:
rake calculate:add[10,20]
Biến ENV:
task :add_env do
puts ENV['NUM1'].to_i + ENV['NUM2'].to_i
end
Chạy thử task:
rake calculate:add_env NUM1=1 NUM2=20
Default Rake task
Nếu không chỉ rõ task được chạy thì Rake sẽ chạy default task được định nghĩa trong Rakefile. Bạn có thể định nghĩa 1 default task như sau:
Rakefile
task :default => ["my_default_task"]
Sau đó, khi chạy lệnh rake
, Rake sẽ mặc định chạy task my_default_task
Làm việc với File
Rake cung cấp 1 số câu lệnh hữu ích như:
ruby
: để chạy 1 file rubysh
: để chạy 1 lệnh trên system commands
Rake còn tích hợp module FileUtils
cho ta có hàng loạt method thao tác với file như cp
, mkdir
, rm
, mv
..
Ví dụ, copy file exam.rb
sang file exam_copy.rb
dùng rake task:
task :copy do
FileUtils.cp "exam.rb", "exam_copy.rb"
end
Bạn có thể xem thêm về module FileUtils
tại đây
Ví dụ thực tế sử dụng Rake
Triết lý của Rake là gom nhóm và tự động hóa các task nhỏ, vì vậy ta có thể định nghĩa ra các task để giúp quá trình phát triền project trở nên nhanh gọn hơn.
Ví dụ, khi init project rails, ta cần duplicate các file chứa thông tin cần bảo mật:
config/database.yml
config/credentials.yml.enc
config/storage.yml
Đổi tên chúng thành đuôi .example
và thêm vào .gitignore
.
Ngoài ra, ta cũng muốn xóa bỏ comment, các dòng trống, chuyển nháy đơn sang nháy kép trong một số file.
Ok, vậy mình sẽ viết task để thực hiện tự động việc đó:
namespace :file do
desc "Create example file"
task :create_example do
gitignore = File.open Rails.root.join(".gitignore"), "a"
file_names = [
"config/database.yml",
"config/credentials.yml.enc",
"config/storage.yml"]
file_names.each do |file|
FileUtils.cp file, file + ".example"
gitignore << file + "\n"
end
gitignore.close
end
desc "Remove default comments"
task :rm_comment do
file_names = ["Gemfile", "config/application.rb"]
file_names.each do |file_name|
text = File.read file_name
# Xoa comment
new_contents = text.gsub(/^\s*#.*/, "")
# Chuyen nhay don => nhay kep
new_contents.gsub!(/'/, '"')
# Xoa dong thua
new_contents.gsub!(/^$\n/, "")
puts new_contents
File.open(file_name, "w") {|file| file.puts new_contents }
end
end
end
Mỗi khi muốn tạo file .example
, ta chỉ cần chạy rake file:create_example
là xong :v Rất chính xác và tiết kiệm thời gian phải không
Kết luận
Mình đã trình bày xong về cách sử dụng cơ bản của Rake và những ví dụ mình thấy là cần thiết dùng Rake. Mong rằng các bạn sẽ có thể sử dụng Rake task vào project của riêng mình
Tài liệu tham khảo
All rights reserved