วันนี้นั้งคุยกะพี่มาย (พี่ที่ทำงาน) ว่า เราน่าจะมาสร้าง rake task ของตัวเองเพื่อเก็บไว้ใช้กับโปรเจคใหม่ๆที่เรากำลังจะทำ จะได้เข้า DRY concept ซะหน่อย ก็เลยนั้งค้นหาบทความเก่าๆที่พูดถึงเกี่ยวกับ Rake พอดีไปเจอกับบทความของ RailsEnvy ที่เขียนเอาไว้เมื่อปีที่แล้วก็เลยลองมานั้งทำตาม ไม่ยากอย่างที่คิดแหละ มือใหม่ๆ อย่างเราก็พอจะทำตามได้ ก็เลยคิดว่าน่าจะลองเอาบทความนี้มาแปลเป็นไทยเพื่อเพื่อนๆ คนอื่นซะหน่อย

ผมจะไม่พูดถึงประวัติของมันนะครับ เพราะว่ามันยาวถ้าอยากรู้มาถามกานนอกรอบดีกว่า เรามาดูกานดีกว่าว่าเค้าใช้ rake ทำอะไรกานใน project เราจะมายกตัวอย่างกันคราวๆ นะครับ

1. ดึงเอารายชื่อผู้ใช้ออกมาจาก table แล้วเอามาส่งอีเมล
2. คำนวนข้อมูลเพื่อทำรายงานในตอนกลางคืน
3. Backups ข้อมูล
….

และยังมีอีกมากมายที่เราสามารถทำได้ครับ

หลังจากเราเห็นภาพกันคราวๆ แล้วว่าเราจะใช้ไอ้เจ้า rake เนี้ยมาทำอะไรกับโปรเจคเราทีนี้เรามาดูกานว่า rake มันทำงานอย่างไร

So how does rake work already?
ผมขอตั้งปฎิบัติการ (Rake task) หรือว่า ตัวอย่างนี้ว่า
How to get a girl in the pub?? – ทำอย่างไรให้ได้หญิงกลับบ้าน (ฮาๆๆ ดูเถื่อนๆ นะเนี้ย)

มาดูขั้นตอนกันก่อนเลย
1. แน่นอนครับ เล็งเลยว่าคนไหนน่ารัก
2. ส่งยิ้มให้
3. ถามเธอก่อนเพื่อความชัว มีแฟนหรือยังครับ (แต่ถึงมีกูก็จะเอา >.<” ไม่ใช่และ)

.. ฮาๆๆ เอาแค่นี้ก่อน ก่อนที่จะเกินเลย เรามาดูโค้ดกานดีกว่า

task :find_nice_target do
  puts "Hey! i found it at 2 o'clock..."
end

task :give_her_a_smile do
  puts "What's up babe."
end

task :ask_if_available do
  puts "No matter yes or no, we will have fun tonight"
end

หลังจากที่เราทำการปฎิบัติการตามแผนของเราแล้ว (after running Rake Task) ผลลัพธ์ที่ได้

$ rake find_nice_target
=> Hey! i found it at 2 o’clock
$ rake give_her_a_smile
=> What’s up babe.
$ rake ask_if_availavle
=> No matter yes or no, we will have fun tonight

ค่อนข้างเจ๋งเลยทีเดียวนะครับ มีคนถามผมว่าแล้วถ้าเกิดว่าวัยรุ่นใจร้อนอยากจะข้ามขั้นตอนไป ถามเธอว่ามีแฟนเลยจะได้หรือป่าว (ask_if_available) คำตอบคือ ถ้าเป็นชีวิตจริงคงไม่มีใครทำเพราะว่าคงโดนเธอ…. แต่ว่า ถ้าเป็น rake task แน่นอนครับเราทำได้ แล้วเราจะทำอย่างไรละ

So how do I express rake dependencies?
ถ้าเราอยากจะข้ามขั้นตอนโดยไม่ให้โดนเธอ…. แล้วละก็ เราก็ต้องทำแบบนี้นะคร้าบ

task :find_nice_target do
  puts "Hey! i found it at 2 o'clock..."
end

task :give_her_a_smile => :find_nice_target do
  puts "What's up babe."
end

task :ask_if_available => :give_her_a_smile do
  puts "No matter yes or no, we will have fun tonight"
end

เพียงแค่นี้เราก็สามารถข้ามขั้นตอนได้โดยไม่ต้องกลัวอีกต่อไปแล้ว เพราะว่ามันจะทำขั้นตอนก่อนหน้าให้อัตโนมัติ

$ rake ask_if_availavle
=> Hey! i found it at 2 o’clock
=> What’s up babe.
=> No matter yes or no, we will have fun tonight

Namespace & Description – ที่นี้เรามาเพิ่งสีสันให้กับปฎิบัติการของเรากันหน่อย โดยการ group หรือให้ namespace กับมัน และเพิ่มคำอธิบายของแต่ละ task ด้วย

namespace :pubmission do
  desc "This task is for finding a nice girl that you like"
  task :find_nice_target do
    puts "Hey! i found it at 2 o'clock..."
  end

  desc "This task is for giving her a signal to tell that u r interesting"
  task :give_her_a_smile => :find_nice_target do
    puts "What's up babe."
  end

  desc "This task is to make sure that it's safe to .... with her"
  task :ask_if_available => :give_her_a_smile do
    puts "No matter yes or no, we will have fun tonight"
  end
end

ลองรัน $ rake --tasks
ผลลัพธ์ที่ได้ก็คือ

ไม่ยากเลยใช่ไหมครับ ที่นี้เราจะมาลองสร้าง task จริงๆ ขึ้นมาใช้กันนะครับ (ขออนุญาติ copy ตัวอย่างของ RailsEnvy มาเลยนะครับ ของเค้าดีอยู่แล้ว)

1. Create a task (ทำการสร้างปฎิบัติการที่เราต้องการ)

สิ่งที่เราจะทำก็คือเราจะสร้าง task ขึ้นมาเพื่อที่จะทำการ create directory สำหรับ image, icon, groups ใน public folder


   desc "Create blank directories if they don't already exist"
   task(:create_directories) do
   # The folders I need to create
    shared_folders = ["icons","images","groups"]

    for folder in shared_folders

       # Check to see if it exists
       if File.exists?(folder)
         puts "#{folder} exists"
       else
         puts "#{folder} doesn't exist so we're creating"
         Dir.mkdir "#{folder}"
       end
     end
  end

2. Save task file (แล้วจะเซฟไว้ที่ไหนละ)
ก่อนอื่น save ไว้ชื่อว่า utils.rake

# ไว้ใน tasks directory เลย
lib/tasks

มาลองเชคกันดูว่าใน rake มี task นี้หรือยัง
$ rake --tasks
ถ้ามีก็จะเห็นแบบนี้ครับ

3. Rake the task (เริ่มปฎิบัติการได้)

$ rake create_directories

ผลลัพธ์ที่ได้ก็คือ

So can I call my Model inside the task?

แล้วถ้าเราต้องการเรียกโมเดลมาใช้ผ่าน task ละ เราจะทำได้ไหม?
คำตอบก็คือ แน่นอนอยู่แล้ว! (เหมือน X-man เลย) และนี้คือสุดที่พวกเราจะใช้มากที่สุดด้วย
เราจะมาดูกานว่าเค้าทำกานอย่างไร (เหมือนเคยตัวอย่างจาก RailsEnvy)

– เราต้องการที่จะค้นหา user ที่กำลังจะหมดอายุ
– ต้องการส่งอีเมลเพื่อทำการเตือน

namespace :utils do
  desc "Finds soon to expire subscriptions and emails users"
  task(:send_expire_soon_emails => :environment) do
        # Find users to email
        for user in User.members_soon_to_expire
                puts "Emailing #{user.name}"
                UserNotifier.deliver_expire_soon_notification(user)
        end
  end
end

เราจะให้ได้ว่าเราตามการเรียกโมเดลผ่าน environment ของเรา

task(:send_expire_soon_emails => :environment) do

เพิ่มเติมอีกนิดนึง อันนี้ผมว่าน่าสนใจ อาจจะมีคนถามว่าถ้าเราต้องการที่จะส่ง parameters ไปให้กับ task และก็แน่นอนอีกแล้วครับ เราสามารถทำได้เหมือนกาน

How do we pass params to task?
ลองสร้าง task เล็กๆขึ้นมา:

desc "test passing params"
task(:shout) do 
  puts ">>>>> #{ENV['word']}"
end

ทำการเรียกคำสั่งโดยส่ง param ไปด้วยชื่อว่า word

$ rake shout word='whats up'

ผลลัพธ์ที่ได้ก้คือ

สำหรับคนที่ต้องการอ่านเพิ่มเติมไปที่ RailsEnvy นะครับ (ตอนทายมีสอน set cron job นิดหน่อย)
ถึงตัวอย่างจะไม่สร้างสรรค์แต่ก็เข้าใจง่าย (รึป่าว?)

credits: RailsEnvy (ของเค้าดีจริง)