我有两个型号
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)。通过上面的解决方案,这意味着每次创建事务都需要调用数据库来检查合同是否存在。有替代方案吗?
如果合同有数千笔交易,这意味着这将被调用数千次,尽管它只与第一笔交易有关。
从一般意义上讲,实现回调的优雅方式是什么。这看起来很乱?
答案 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?
的来电将免费,您无需担心。