【问题标题】:How to handle enum values in rails 4如何处理rails 4中的枚举值
【发布时间】:2014-03-08 17:36:58
【问题描述】:

所以我的数据库中有一个subscription 表。

我希望有一个 state 列,该列将具有以下任一值

Valid
Invalid
Cancelled
In Trial
Non Renewing
Future

有人可以解释如何在 rails 4 中将这些值用作枚举值吗?

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-4


    【解决方案1】:

    归功于:https://hackhands.com/ruby-on-enums-queries-and-rails-4-1/

    声明一个枚举属性,其中值映射到数据库中的整数,但可以通过名称进行查询。示例:

    class Conversation < ActiveRecord::Base
      enum status: [ :active, :archived ]
    end
    
    # conversation.update! status: 0
    conversation.active!
    conversation.active? # => true
    conversation.status  # => "active"
    
    # conversation.update! status: 1
    conversation.archived!
    conversation.archived? # => true
    conversation.status    # => "archived"
    
    # conversation.update! status: 1
    conversation.status = "archived"
    
    # conversation.update! status: nil
    conversation.status = nil
    conversation.status.nil? # => true
    conversation.status      # => nil
    

    还将提供基于枚举字段允许值的范围。使用上面的例子,它将创建一个活动和存档的范围。

    您可以从数据库声明中设置默认值,例如:

    create_table :conversations do |t|
      t.column :status, :integer, default: 0
    end
    

    好的做法是让第一个声明的状态成为默认状态。

    最后,还可以使用哈希显式映射属性和数据库整数之间的关系:

    class Conversation < ActiveRecord::Base
      enum status: { active: 0, archived: 1 }
    end
    

    请注意,当使用数组时,从值到数据库整数的隐式映射是根据值在数组中出现的顺序得出的。在示例中,:active 映射为 0,因为它是第一个元素,而 :archived 映射为 1。一般情况下,第 i 个元素映射到数据库中的 i-1。

    因此,一旦一个值被添加到枚举数组中,它在数组中的位置必须保持不变,新的值应该只添加到数组的末尾。要删除未使用的值,应使用显式 Hash 语法。

    在极少数情况下,您可能需要直接访问映射。映射通过具有复数属性名称的类方法公开:

    Conversation.statuses # => { "active" => 0, "archived" => 1 }
    

    当您需要知道枚举的序数值时,使用该类方法:

    Conversation.where("status <> ?", Conversation.statuses[:archived])
    

    枚举属性的条件必须使用枚举的序数值。

    更多信息:http://api.rubyonrails.org/v4.1.0/classes/ActiveRecord/Enum.html

    【讨论】:

    • 不幸的是,这只适用于 rails4.1。我暂时不想将我的应用升级到 rails 4.1。
    • @cevaris 我最初从 rails 文档页面复制了该答案。不是来自您提到的链接。我希望 rails 从你提到的源代码中复制了代码
    【解决方案2】:

    您可以使用名为 Workflow 的 gem。它使您能够使用自定义状态并优雅地处理状态之间的转换。我在许多 Rails3 和 Rails 4 应用程序中使用过它。

    文档中的示例。

    class Article
      include Workflow
      workflow do
        state :new do
          event :submit, :transitions_to => :awaiting_review
        end
        state :awaiting_review do
          event :review, :transitions_to => :being_reviewed
        end
        state :being_reviewed do
          event :accept, :transitions_to => :accepted
          event :reject, :transitions_to => :rejected
        end
        state :accepted
        state :rejected
      end
    end
    

    后来:

    article = Article.new
    article.accepted? # => false
    article.new? # => true
    

    【讨论】:

      【解决方案3】:

      编辑: 我在这里的回答不使用ActiveRecord magic enums。我在下面的建议适用于任何数据库库(如Sequel),我碰巧认为它更健壮。例如,它不依赖于值的自动排序,它使用 RDBMS 中的外键约束来确保您的值是有效的(与 ActiveRecord 解决方案不同)。但是,这不是 Rails 惯用的方法。请参阅 Giri 的答案(文档页面的副本/粘贴)以获得惯用答案。


      1. 在您的数据库中创建一个 states 表,其中填充了这些字符串值以及唯一 ID,例如

        states
        id | name 
        ---+--------------
         1 | Valid
         2 | Invalid
         3 | Cancelled
         4 | In Trial
         5 | Non Renewing
         6 | Future
        
      2. subscription 表中使用标准外键关联,引用来自 states 的条目。

      3. 在您的模型中,使用与 ID 匹配的常量创建一个 State 类,例如:

        class State < ActiveRecord::Base
          VALID   = 1
          INVALID = 2
          # etc.
        end
        

      现在你 a) 保证你的表数据是有效的,并且 b) 你可以使用方便的引用,例如要求 subscriptions

      Subscription.where( state_id: State::VALID )
      

      【讨论】:

      • 这不是 Rails 4 处理枚举的方式。你的答案没有错,但不是操作问题需要的 Rails 4 方式……看看api.rubyonrails.org/v4.1.0/classes/ActiveRecord/Enum.html
      • @rizidoro 谢谢你的信息。我个人认为 Rails 方式不太理想,因为它依赖于在 Ruby 而不是数据库中强制引用完整性。 Giri:请将接受的答案切换为您的 Rails 文档的副本/粘贴。
      • 我不喜欢将 ID 硬编码为常量的想法。它将您的代码与数据库中的数据相结合。我过去曾这样做过,当我必须将应用程序部署到多个环境(单独的数据库)或编写自动化测试时,我非常讨厌它......另外我会避免使用整数作为状态,你会发现当您必须编写自定义查询或扩展时,它非常违反直觉,并且您无需查看代码就无法回忆起哪个数字意味着哪个。
      猜你喜欢
      • 1970-01-01
      • 2021-09-02
      • 2016-08-02
      • 1970-01-01
      • 2015-12-03
      • 1970-01-01
      • 2014-10-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多