在Rails中优雅替代after_create回调?

时间:2013-11-01 01:09:00

标签: ruby-on-rails activerecord

我有两个型号

class Contract < ActiveRecord::Base
  has_many :transactions
end

class Transaction < ActiveRecord::Base
  belongs_to :contract
  after_create :mark_contract_as_live
  def mark_contract_as_live
    k = self.contract
    if !k.is_live
      k.update_attributes(:is_live => true)
    end
  end
end

is_live是Contract模型中的布尔字段。合同默认为创建时不会生效(is_live =&gt; false)。当记录第一个交易时,它被标记为实时(is_live =&gt; true)。通过上面的解决方案,这意味着每次创建事务都需要调用数据库来检查合同是否存在。有替代方案吗?

如果合同有数千笔交易,这意味着这将被调用数千次,尽管它只与第一笔交易有关。

从一般意义上讲,实现回调的优雅方式是什么。这看起来很乱?

1 个答案:

答案 0 :(得分:4)

class Contract < ActiveRecord::Base
  has_many :transactions

  def mark_as_live
    update(is_live: true) unless is_live?
  end
end

class Transaction < ActiveRecord::Base
  belongs_to :contract

  after_create :mark_contract_as_live

private

  def mark_contract_as_live
    contract.mark_as_live
  end
end

Contract职业责任是关心合同是否应标记为现场。 Transaction类不应该处理这个问题。所以我在mark_as_live课程中创建了Contract,并在Transaction after_create回调中调用它。

我更喜欢在mark_as_live方法中使用保护条款,如下所示:

def mark_as_live
  return if is_live?

  update(is_live: true)
end

但是因为它是一种非常短的方法,它可能不值得。

另请注意,ActiveRecord为布尔字段添加了xxx?等方法。方法结尾处的问号更清楚地表达了您想说的内容。

最后,但这是一个品味问题,我不喜欢用is_xxx为我的布尔属性添加前缀。我不使用RSpec可能是错误的,但我认为它为be_xxx属性添加了一些谓词匹配器,例如xxx,它可能会对is_xxx属性产生奇怪的影响。因为很多人都在使用RSpec,所以它可能会成为一种惯例。

  

如果合同有数千笔交易,这意味着这将被调用数千次,尽管它只与第一笔交易有关。

如果您创建如此的事务,Contract实例仍会被加载:contract.transactions.create(transaction_params)。因此,is_live?的来电将免费,您无需担心。