【问题标题】:Run Rake Task without using Rake在不使用 Rake 的情况下运行 Rake 任务
【发布时间】:2012-11-08 20:49:17
【问题描述】:

我有一个应用程序,用户可以在其中互相下注,当结果加载到应用程序中时,我使用 Rake 任务来结算赌注。我在 Heroku 上运行,所以我每半小时使用他们的调度服务来执行这个 Rake 任务。

这很好用,但我更希望在数据库中保存/更新结果时运行 Rake 作业。

如何转换 Rake 任务,以便可以从我的模型中运行它,如下所示。如果我可以从控制器运行它也可能会很好,因为我可能有几种需要结算过程的情况。

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

  after_save   :settlement
end

我的 Rake 任务现在看起来像这样:

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

【问题讨论】:

  • 你可以把它放在lib的一个文件里,然后在需要的时候调用它。你可以做一些棘手的事情,比如设置观察者来观察模型何时被保存,并做出相应的反应。您还可以使用 PrivatePub 向您的视图发送异步方法来执行提醒用户等操作。
  • 嗨.. 我只是觉得从模型、控制器等运行 Rake 任务并不是最佳实践。它们只能从某种 Cron 调用。我有什么错误的印象吗:)
  • 哦,对不起,我没有很好地解释自己。那是我的错。我的意思是您可以将代码从 rake 任务中取出,并将其放在 lib 的类中。您将不再有 rake 任务。该代码将只是一个常规的 ruby​​ 方法(只是在 lib 中提供,因为它不是模型或任何东西),然后从任何地方调用它。
  • 现在看这更有意义了 :) 你能告诉我libdirectory 中的文件应该是什么样子吗?我在想文件的开头 - 是什么与Module 或应该是'class Spotprice

标签: ruby-on-rails rake helper


【解决方案1】:

如果您希望在更新(或保存)时计算结果,为什么不将大部分代码从您的 rake 任务移动到您的 Bet 模型的方法中,然后通过 after_update 回调调用它

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

spot_price.rb

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

  ....
end

这不处理我们其他输出的 Pusher 东西(保存并返回到 message 变量中)。另外,我忍不住,但我认为您的意思是“Lose”,而不是“Loose”。

这就是你要找的吗?

【讨论】:

  • 很有道理,但我有不止一个班级需要在一次运行中解决,而且我还在运行一项任务,该任务根据用户的奖金对用户进行排名。我想将收集的代码保存在一个地方。顺便感谢您的错字:)
【解决方案2】:

只需将原始问题中的我的 cmets 放入答案中即可。

我有类似的情况,我有一个 rake 任务,我想从 rake 之外调用。您要做的是将代码从 rake 任务移到 ruby​​ 类中,最好的地方是lib。你的课程看起来像这样:

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

然后在代码中你可以做这样的事情(随机示例):

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

或者(另一个随机例子):

# 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

如果你愿意,你仍然可以使用 rake 任务:

# 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

【讨论】:

  • 现在看来要走的路了。我会试一试,看看能不能让它工作,然后回复你:) 谢谢!
  • 完美......就像我想要的那样工作......非常感谢你:)祝你有美好的一天!
  • 我建议将额外的文件添加到autoload_path。 (stackoverflow.com/questions/1223481/…)
猜你喜欢
  • 1970-01-01
  • 2012-11-15
  • 2010-10-09
  • 1970-01-01
  • 2014-12-05
  • 1970-01-01
  • 2011-06-20
  • 1970-01-01
  • 2012-05-30
相关资源
最近更新 更多