Rails 中 after_create 回调的优雅替代品?

sam*_*mol 3 activerecord ruby-on-rails

我有两个模型

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
Run Code Online (Sandbox Code Playgroud)

is_live 是 Contract 模型中的布尔字段。合约在创建时默认为无效(is_live => false)。当第一笔交易被记录时,它被标记为实时(is_live => true)。有了上面的解决方案,这意味着每个交易创建都需要调用数据库来检查合约是否有效。有没有替代方法?

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

一般来说,什么是实现回调的优雅方式。这看起来很乱?

Dam*_*ien 5

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
Run Code Online (Sandbox Code Playgroud)

Contract关心合约是否应该被标记为有效是班级的责任。这个Transaction类不应该处理这个。所以我mark_as_liveContract类中创建了一个并在Transaction after_create回调中调用它。

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

def mark_as_live
  return if is_live?

  update(is_live: true)
end
Run Code Online (Sandbox Code Playgroud)

但是因为它是一个很短的方法,所以它可能不值得。

还要注意ActiveRecord添加了像xxx?布尔字段这样的方法。方法末尾的问号更清楚地传达了您想说的内容。

最后,但这是一个品味问题,我不喜欢在布尔属性前加上is_xxx. 我不使用RSpec,可能是错的,但我认为,它增加了一些谓词的匹配一样be_xxxxxx属性,它可能会用怪异的is_xxx属性。因为很多人都在使用RSpec,所以它可能会成为一种惯例。

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

Contract实例将如果你创建了像这样一个事务中仍然加载:contract.transactions.create(transaction_params)。因此is_live?,您可以免费拨打电话,您不必担心。