Twiddr
Twiddr

Reputation: 297

Run Rake Task without using Rake

I have an app where users can bet each other and when the result are loaded into the app I use a Rake task to settle the bets. I'm running on Heroku so I'm using their Schedule service for this Rake task every half hour.

This works fine, but I would much more like to run the Rake job when the results are saved/updated in the database.

How do I convert the Rake task so I can run it from my model, which could look like the below. It could also be nice if I could run it from the controllers, since I might have several situations where a settlement process is needed.

class Spotprice < ActiveRecord::Base
  belongs_to :spotarea
  belongs_to :product

  after_save   :settlement
end

My Rake task looks like this right now:

task :settlement => :environment do
  puts "Settlement in progress..."
  puts "-------------------------"
  puts " "
  puts " "
  puts "BETS:"
  puts "-------------------------"

  # Bet settlement
  @bets = Bet.where(:settled => false)

  @bets.find_each do |bet|

    if not bet.choice.spotprice.nil?

      case 
      when bet.choice.spotprice.value > bet.choice.value && bet.buy == true
        profitloss  = 10
        puts "#{bet.id}: Win (1)"
      when bet.choice.spotprice.value < bet.choice.value && bet.buy == false 
        profitloss  = 10
        puts "#{bet.id}: Win (2)"
      when bet.choice.spotprice.value > bet.choice.value && bet.buy == false
        profitloss  = -10
        puts "#{bet.id}: Loose (3)"
      when bet.choice.spotprice.value < bet.choice.value && bet.buy == true 
        profitloss  = -10
        puts "#{bet.id}: Loose (4)"
      when bet.choice.spotprice.value == bet.choice.value
        profitloss  = -10
        puts "#{bet.id}: Loose (5)"
      end

      if profitloss  
        bet.settled    = true
        bet.profitloss = profitloss 
        bet.save
      end 

    end

    if bet.choice.settled == true
      bet.choice.settled = false
      bet.choice.save
    end

  end

  # Pusher update
  Pusher["actives"].trigger("updated", {:message => "Settlement completed"}.to_json)

end

Upvotes: 1

Views: 379

Answers (2)

MrDanA
MrDanA

Reputation: 11647

Just putting my comments from the original question in to an answer.

I had a similar situation where I had a rake task that I wanted to call from outside of rake. What you want to do is move the code from the rake task in to a ruby class, the best place for this would be in lib. Your class would look something like this:

# lib/settlement.rb
class Settlement
  def self.settle_bets
    # all the code that used to be in the rake task
  end
end

Then in code you can do something like this (random example):

# app/controllers/bets_controller.rb
#...
  def settle_bets
    require "settlement"
    Settlement.settle_bets
  end
# ...

Or (another random example):

# app/models/bet.rb
class Bet ...
  after_update: update_some_bets

  # ... more code here

  private
    def update_some_bets
      require "settlement"
      Settlement.settle_bets
    end

And you could still use the rake task if you wanted:

# lib/tasks/settlement.task
require "settlement"
# require "#{Rails.root}/lib/settlement.rb" # use this if the above won't work

task :settlement => :environment do
  Settlement.settle_bets
end

Upvotes: 1

Tom Harrison
Tom Harrison

Reputation: 14068

If you want the results calculated when you update (or save), why not move most of the code from your rake task into a method of your Bet model, then call it which you call with an after_update callback

in bet.rb

# class method that settles the given bet
def self.settle(bet)
  message = nil
  if not bet.choice.spotprice.nil?
    case 
    when bet.choice.spotprice.value > bet.choice.value && bet.buy == true
      profitloss  = 10
      message =  "#{bet.id}: Win (1)"
    when bet.choice.spotprice.value < bet.choice.value && bet.buy == false 
      profitloss  = 10
      message =  "#{bet.id}: Win (2)"
    when bet.choice.spotprice.value > bet.choice.value && bet.buy == false
      profitloss  = -10
      message =  "#{bet.id}: Lose (3)"
    when bet.choice.spotprice.value < bet.choice.value && bet.buy == true 
      profitloss  = -10
      message =  "#{bet.id}: Lose (4)"
    when bet.choice.spotprice.value == bet.choice.value
      profitloss  = -10
      message =  "#{bet.id}: Lose (5)"
    end

    if profitloss  
      bet.settled    = true
      bet.profitloss = profitloss 
      bet.save
    end 
  end

  if bet.choice.settled == true
    bet.choice.settled = false
    bet.choice.save
  end
  # return message
  message
end

in spot_price.rb

class SpotPrice
  after_update Bet.settle(self)
  after_save   Bet.settle(self)

  ....
end

This doesn't handle the Pusher stuff our other output (which is saved and returned in the message variable). Also, couldn't help myself, but I assumed you mean "Lose", not "Loose".

Is this what you're looking for?

Upvotes: 0

Related Questions