提问人:Yan 提问时间:8/8/2023 更新时间:8/9/2023 访问量:60
检查 Rails 7 中新创建的记录是否覆盖默认值的更改
Check for changes that override default on newly created record in Rails 7
问:
对于我们的应用程序,我以两种方式新创建记录:
- 使用数据库中的默认值。
- 手动设置属性。
我需要区分这些更改,以便知道该属性是手动覆盖的,还是因为它是默认属性而设置的。
我正在将回调与检查更改
的方法一起使用,但此方法无法区分这两种方案。当涉及到方法时,这两行是相等的(我正在使用 Minitest 和 FactoryBot 来表达我的观点):before_validation
on: :create
changes
# Table name: users
# admin :boolean default(FALSE), not null
FactoryBot.create(:user, admin: false)
FactoryBot.create(:user)
有没有办法让我做出区分?
答:
0赞
smathy
8/9/2023
#1
一个技巧是利用这样一个事实,即如果默认值提供值,则 Rails 不使用 setter 方法。因此,您可以覆盖 setter 并设置一些其他属性来指示这是由调用方设置的:
def initialize(*)
@default_admin = true
super
end
def default_admin?; @default_admin; end
def admin=(*)
@default_admin = false
super
end
此外,还为以下行业工作的额外优势:
u = User.new
u.admin = false
0赞
Vladimir Krivchenko
8/9/2023
#2
布尔列只有 3 个可能的值:true、false 和 NULL。不可能(至少以任何有意义的方式)区分 false 和 false,您需要更多数据。
最简单的方法是使用 NULL 作为默认值。Rails 认为 NULL 是“虚假的”,因此这些用户不会获得管理员权限,但你可以很容易地分辨出区别:NULL - 默认的;FALSE - 显式。
0赞
Alex
8/9/2023
#3
>> User.new(admin: false).admin_changed?
=> false
>> User.new(admin: false).admin_came_from_user?
=> true
您也可以在触摸某个属性时强制更改,即使它实际上没有更改:
class User < ApplicationRecord
def admin=(_value)
admin_will_change!
super
end
end
>> User.new(admin: false).admin_changed?
=> true
>> User.new(admin: false).changes
=> {"admin"=>[false, false]}
在每次更改跟踪属性之前调用。
[attr_name]_will_change!
评论