Rails 3 app model如何确保一次只将一个布尔字段设置为true

时间:2012-04-13 03:36:14

标签: ruby-on-rails ruby

我有一个Logo模型,其中包含name:string,default:boolean。我希望真值是唯一的,这样数据库中只有一个项可以一次设置为true。如何在我的控制器中设置更新和新操作以将我的徽标的所有其余值设置为false?

我们说我有以下设置 在我的数据库中 型号标志
name:string |默认值:布尔值|
Item1 |真|
Item2 |假|
Item3 |假|

如果我将Item2默认值更改为true,我希望它循环遍历所有徽标并将其余徽标设置为false,因此一次只有一个是真的,所以它看起来像这样。

name:string |默认值:布尔值|
Item1 |假|
Item2 |真|
Item3 |假|

感谢您提前提供任何帮助。

8 个答案:

答案 0 :(得分:20)

此代码在之前的回答中被盗,并略有简化:

def falsify_all_others
  Item.where('id != ?', self.id).update_all("default = 'false'")
end

您可以在模型的before_save回调中使用此方法。

实际上,最好只“伪造”哪些值为'真'的记录,如下所示:

Item.where('id != ? and default', self.id).update_all("default = 'false'")

更新:要保持代码干,请使用self.class代替Item

self.class.where('id != ? and default', self.id).update_all("default = 'false'")

答案 1 :(得分:5)

我认为在你伪造别人之前检查你保存的那个是否真实是件好事。否则,当您保存未激活的记录时,您会伪造所有人。

def falsify_all_others
    if self.default
        self.class.where('id != ? and default', self.id).update_all("default = 'false'")
    end
end

答案 2 :(得分:3)

在您的控制器代码中,您可以执行类似的操作....请注意您可能将Item2作为参数[...],以便您可以在下面进行交换

@items_to_be_falsified = Item.where('id != ?', Item2.id)

@items_to_be_falsified.each do |item|
  item.default = false
  item.save
end

请注意,当您开始使用此功能时,将其移至模型中的良好做法是将其转换为函数并将其称为Item2.falsify_all_others,如下所示

def falsify_all_others
  Item.where('id != ?', self.id).each do |item|
    item.default = false
    item.save
  end
end

享受!

答案 3 :(得分:3)

我还建议伪造所有记录,然后将它们设为真。

add_column :users, :name ,:boolean, default: false

答案 4 :(得分:3)

好的还有一些你需要的东西。

不要使用字段名称default,它通常是为数据库保留的。 保存默认为false的记录会将所有记录设置为false,这不是您想要的。检查我们是否将此记录设置为true并将其设置为falseify。

  before_save :falsify_all_others
  def falsify_all_others
    if is_default
      self.class.where('id != ?', self.id).where('is_default').update_all(:is_default => false)
    end
  end

答案 5 :(得分:1)

如果你想让它用于创建和更新(rails v4) 记下来自rails guides

的这个花絮
  

after_save在创建和更新时运行,但总是在更多之后运行   无论顺序如何,具体的回调都是after_create和after_update   其中执行了宏调用。

答案 6 :(得分:0)

如果您是最近来这里并使用Rails 6,则应该在数据库级别和模型级别都涉及到这一点:

数据库级别:

add_index :items, :default, unique: true, where: '(default IS TRUE)', algorithm: :concurrently

模型级别:

class Item < ApplicationRecord
  scope :default, -> { where(default: true) }

  validates :default, uniqueness: { conditions: -> { default } }
end

答案 7 :(得分:0)

class Model < ApplicationRecord
  before_save :ensure_single_default, if: :is_default?

  private

  def ensure_single_default
    self.class.update_all(is_default: false)
  end
end

您不需要检查ID,因为此回调发生在保存真实回调之前。