sinsoku
2015/11/24 16:58:10 投稿
0

rakeタスクの処理を別クラスで定義する

Railsでrakeタスクを作るときにクラスを作っておくとテストしやすくて便利。

rakeタスクのテストをする方法もあるけど、クラスに抽出すればメソッド単位で細かくテストが出来るのでTDDしやすい。

あと、細かいところで find_each を使ったり、 ActiveRecord::Base.transaction の修正もしてる。

Before

# lib/tasks/item_deliver.rake
namespace :item do
  desc 'deliver items to users (UESR_IDS=1,2,3 ITEM_IDS=1,2 MESSAGE="11/24(火)より障害が...")'
  task deliver: :environment do
    user_ids = ENV['UESR_IDS']
    item_ids = ENV['ITEM_IDS'].try!(:split, ',')
    message = ENV['MESSAGE']

    fail 'USER_IDの指定がありません' unless user_id
    fail 'ITEM_IDSの指定がありません' unless item_ids
    fail 'MESSAGEの指定がありません' unless message

    Rails.logger.info('start: rake item:deliver')

    users = User.where(id: user_ids)
    users.each do |u|
      items = Item.where(id: item_ids)
      items.each do |item|
        u.items << items
      end
      u.messages.create!(body: message)

      Rails.logger.info("#{u.id}: delivered")
    end

    Rails.logger.info('finish: rake item:deliver')
  end
end

After

# lib/tasks/item_deliver.rake
namespace :item do
  desc 'deliver items to users (UESR_IDS=1,2,3 ITEM_IDS=1,2 MESSAGE="11/24(火)より障害が...")'
  task deliver: :environment do
    require 'lib/item_deliver_task'
    ItemDeliverTask.run
  end
end

# lib/item_deliver_task.rb
class ItemDeliverTask
  def self.run
    Rails.logger.info('start: rake item:deliver')
    new.run
    Rails.logger.info('finish: rake item:deliver')
  end

  def initialize
    @user_ids = ENV['UESR_IDS']
    @item_ids = ENV['ITEM_IDS'].try!(:split, ',')
    @message = ENV['MESSAGE']
  end

  def validate_params!
    fail 'USER_IDの指定がありません' unless @user_ids
    fail 'ITEM_IDSの指定がありません' unless @item_ids
    fail 'MESSAGEの指定がありません' unless @message
  end

  def run
    validate_params!
    User.where(id: @user_ids).find_each { |u| deliver_to(u) }
  end

  def items
    @items ||= Item.where(id: @item_ids)
  end

  def deliver_to(user)
    ActiveRecord::Base.transaction do
      user.items << items
      user.messages.create!(body: @message)
    end
    Rails.logger.info("#{user.id}: delivered")
  end
end

みんなのコメント

hanachin
hanachin
2015/11/25 12:59:34 投稿

validate_params!メソッドの1行目@user_idになってますけど@user_idsのtypoかも?

sinsoku
sinsoku
2015/11/26 15:13:05 投稿

@hanachin_ たしかに!直しておきます