检查 Rails 7 中新创建的记录是否覆盖默认值的更改

Check for changes that override default on newly created record in Rails 7

提问人:Yan 提问时间:8/8/2023 更新时间:8/9/2023 访问量:60

问:

对于我们的应用程序,我以两种方式新创建记录:

  1. 使用数据库中的默认值。
  2. 手动设置属性。

我需要区分这些更改,以便知道该属性是手动覆盖的,还是因为它是默认属性而设置的。

我正在将回调与检查更改的方法一起使用,但此方法无法区分这两种方案。当涉及到方法时,这两行是相等的(我正在使用 Minitest 和 FactoryBot 来表达我的观点):before_validationon: :createchanges

# Table name: users
# admin       :boolean          default(FALSE), not null

FactoryBot.create(:user, admin: false)
FactoryBot.create(:user)

有没有办法让我做出区分?

Ruby-on-Rails 验证 Ruby-on-Rails-7 ActiveModel

评论


答:

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

他们只是忘了告诉我们:https://github.com/rails/rails/blob/v7.0.6/activerecord/lib/active_record/attribute_methods/before_type_cast.rb#L33


您也可以在触摸某个属性时强制更改,即使它实际上没有更改:

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!

https://api.rubyonrails.org/classes/ActiveModel/Dirty.html