如何在Rails中拥有互斥列?

时间:2015-11-21 17:22:42

标签: ruby-on-rails postgresql

我不确定用这句话的最好方法,所以让我来说明一下:

class Foo < ActiveRecord::Base
  belongs_to :organization
  enum state: [:active, :inactive]
end

如果我将任何foo更新为:active,我需要将同一组织中的所有其他Foo更改为:inactive

但是,我不想过于急切,如果将Foo更改为active,则无法通过某种验证或以其他方式回滚。另一方面,我不能同时拥有两个Foos :active

我计划在after_commit挂钩中发送通知。但是如果我在after_update挂钩内更新:active模型为:inactive,那么我不知道是否仍会在主要事务内部对那些模型触发after_commit挂钩

3 个答案:

答案 0 :(得分:1)

由于存在违反您的唯一约束并仅在经过一些检查后应用它的情况,我不建议查看数据库约束/条件唯一索引,除非您绝对想要解决竞争条件。< / p>

我认为如果你在你的模型中加入类似下面的东西,它应该可以工作:

class Foo < ActiveRecord::Base
  # the following should be your last callback
  after_update :unique_state

  # replacing the enum with an easy-to-understand scope
  scope :active, -> { where(state: true) }

  private

  def unique_state
    # do nothing if state is false:
    return unless state

    Foo
    .active
    .where(organization_id: organization_id)
    .where.not(id: id)
    .update_all(state: false)
  end
end

答案 1 :(得分:1)

我将上述评论复制为您问题的答案:

我认为不是在state表中使用foos列,active_foo_id中的organizations列会更好:)您只需要在需要时更新一条记录改变国家。

答案 2 :(得分:0)

我通过将列更改为名为active_as_of的日期时间来解决此问题。通过简单的touch(:active_as_of)实现特定记录的活动,并消除了多个活动记录的可能性。

这也解决了删除或停用活动记录的情况。在这种情况下,最近最活跃的记录将不间断地恢复其活动状态。

相关问题