【问题标题】:Rails 5: read-only enum attributeRails 5:只读枚举属性
【发布时间】:2017-05-07 06:03:14
【问题描述】:

我有一个由多个类使用的模块,其enum 属性verification_status

included(self) do
  enum verification_status: { dont_verify: 0, pending: 1, in_review: 2, rejected: 3, approved: 4 }
end

我希望这个属性是只读的,除非通过一种专用方法,否则无法修改它,即它应该失败并返回一些错误。这里的原因是我需要修改它作为另一个属性修改的结果,所以当有人在可验证对象上调用add_verification(这是专用方法)时,Verification 与一些属性被添加到该对象的先前验证列表中,并且其状态被设置为该对象的verification_status

我知道attr_readonly,但这并没有真正涵盖我关心的所有情况。提前致谢!

【问题讨论】:

    标签: ruby-on-rails enums ruby-on-rails-5


    【解决方案1】:

    标准 Rails 代码不支持只读枚举,因此请将以下内容视为一种 hack。枚举值一般可以通过两种方式设置:

    • 通过直接为枚举列名称设置一个值 - 正如您所说,可以使用attr_readonly 抑制这种行为,但我想没有任何方法可以真正设置枚举值;这就是为什么我们宁愿自己重新定义 setter 方法,并且
    • 通过调用record.enum_value! - bang 方法是动态定义的,必须重新定义以引发错误而不是设置值。

    因此,在声明enum 之后,您需要重新定义setter 方法,如下所示:

    enum verification_status: { dont_verify: 0, pending: 1, in_review: 2, rejected: 3, approved: 4 }
    
    # redefine the enum setter  
    define_method("verification_status=") do |args = nil|
      raise "use `add_verification` instead to modify this"
    end
    
    # redefine the bang enum setters
    verification_statuses.each do |status, value|
      define_method("#{status}!") do
        raise "use `add_verification` instead to modify this"
      end
    end
    

    那么,要真正设置枚举值,需要使用直接设置属性的私有write_attribute方法,使用数字枚举值,例如:

    write_attribute(:verification_status, self.class.verification_statuses[:pending])
    #=> 1
    
    # verify that the value has been indeed set
    verification_status
    #=> "pending"
    

    【讨论】:

    • 我对@9​​87654328@ 方法的正确性有一个疑问。有没有更优雅/正确的方法来做到这一点(最后调用save对我来说看起来很奇怪):def add_verification(verification)write_attribute(:verification_status, Verification.statuses[verification.status])verifications << verificationsaveend如果我理解正确,write_attribute只会修改内存中的属性,而不将其保存到数据库中。这就是我打电话给save 的原因(抱歉格式不好,这是我能做的最好的)。
    • 正确,write_attribute 只在内存中设置属性,你必须调用save。为什么你觉得奇怪? save 保存所有更改的属性(如果有),而不仅仅是验证状态,这一事实可能存在问题。如果您愿意,也可以使用update_column 方法,直接在db 中设置属性,更多信息请参见docs
    • 我现在无法检查,但我认为这里的<< 也保存了对verifications 数组所做的更改。因此,如果我使用save,则会出现重复的数据库更新,对吗?如果我是,update_column 在这种情况下是更好的方法。 Díky!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-19
    • 2018-02-04
    相关资源
    最近更新 更多