16

我有一个徽标模型,其中包含名称:字符串,默认值:布尔值。我希望 true 值是唯一的,以便一次只能将数据库中的一项设置为 true。如何在我的控制器中设置我的更新和新操作以将我的徽标的所有其余值设置为 false?

假设我的数据库中有以下设置
模型徽标
名称:字符串 | 默认值:布尔值 |
项目1 | 真实 |
项目2 | 假 |
项目3 | 假 |

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

名称:字符串 | 默认值:布尔值 |
项目1 | 假 |
项目2 | 真实 |
项目3 | 假 |

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

4

9 回答 9

22

此代码是从先前的答案中窃取的,并略有简化:

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'")
于 2012-04-13T05:46:33.480 回答
5

我认为在你伪造别人之前检查你保存的是否是真的很好。否则,当您保存不活动的记录时,您会伪造所有人。

def falsify_all_others
    if self.default
        self.class.where('id != ? and default', self.id).update_all("default = 'false'")
    end
end
于 2015-02-02T18:05:42.473 回答
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

享受!

于 2012-04-13T03:40:08.787 回答
3

我还建议您伪造所有记录,然后将其变为真实。

add_column :users, :name ,:boolean, default: false
于 2012-08-03T08:14:00.820 回答
3

好的,您还需要一些东西。

不要使用默认的字段名称,它通常为数据库保留。将默认记录保存为 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
于 2014-08-29T15:21:49.903 回答
2

如果您是最近才来到这里并使用 Rails 6,则应该在数据库级别和模型级别上对此进行介绍:

数据库级别:

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

型号等级:

class Item < ApplicationRecord
  scope :default, -> { where(default: true) }
  
  validates :default, uniqueness: { conditions: -> { default } }
end
于 2020-03-26T09:04:07.057 回答
1

如果您希望它可以用于创建和更新(rails v4),请记下rails guides中的这个花絮

after_save 在 create 和 update 时都运行,但总是在更具体的回调 after_create 和 after_update 之后运行,无论宏调用的执行顺序如何。

于 2016-01-28T03:25:42.290 回答
1
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,因为此回调发生在保存真实值之前。

于 2020-09-17T15:18:10.347 回答
1

更多 ActiveRecord,更少原始 SQL 决策

after_commit :reset_default, if: :default?

private

def reset_default
  self.class.where.not(id: id).where(default: true).update_all(default: false)
end
于 2022-01-24T12:00:48.863 回答