我有一个模型,其中包含
name:string
、default:boolean
字段。我希望 true
值是唯一的,以便一次只能将数据库中的一项设置为 true。如何在控制器中设置更新和新操作以将项目的所有其余值设置为 false
?
假设我的数据库中有以下设置
name:string | default:boolean |
Item1 | true |
Item2 | false |
Item3 | false |
如果我将
Item2
默认值更改为 true,我希望它循环遍历所有项目并将其余项目设置为 false
,因此一次只有一个是 true
,所以看起来像这样。
name:string | default:boolean |
Item1 | false |
Item2 | true |
Item3 | false |
此代码是从以前的答案中窃取并稍微简化的:
def falsify_all_others
Item.where('id != ?', self.id).update_all("default = 'false'")
end
您可以在模型中的 before_save 回调中使用此方法。
实际上,最好只“伪造”那些值为“true”的记录,如下所示:
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'")
我觉得在你伪造别人之前先检查一下你保存的是否是真的是很好的。否则,当您保存不活跃的记录时,您就会伪造所有人。
def falsify_all_others
if self.default
self.class.where('id != ? and default', self.id).update_all("default = 'false'")
end
end
在您的控制器代码中,您可以执行类似的操作...请注意,您可能将 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
享受吧!
我还建议伪造您的所有记录,然后使其真实。
add_column :users, :name ,:boolean, default: false
好的,您还需要一些东西。
不要使用默认字段名称,它通常是为数据库保留的。 将记录保存为默认值 false 会将所有记录设置为 false,这不是您想要的。检查我们是否将此记录设置为 true 并设置为 false。
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
更多 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
如果您最近来到这里并且正在使用 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
如果您希望它用于创建和更新(rails v4) 记下 rails 指南
中的这个花絮after_save 在创建和更新时运行,但总是在 more 之后运行 特定回调 after_create 和 after_update,无论顺序如何 其中执行了宏调用。
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,因为此回调发生在保存 true 之前。