【问题标题】:Proper storage of "enumeration" models in Rails在 Rails 中正确存储“枚举”模型
【发布时间】:2010-11-15 22:43:12
【问题描述】:

抱歉,如果问题有点不准确,但我将在下面描述我的问题。

我在 Rails 项目中设置一些模型,我注意到我多次遇到的一件事是处理满足以下条件的属性:

  • 可以将它们设置为一组小的预定义值中的一个
  • 这些值需要同时具有名称和标识符(无论是数字 id、代码等)
  • 这些值只会随着大量代码更改而改变。

例如,我的一个模型应该有一个status 字段,可以设置为以下之一:正在定义、已执行或已完成。我需要在界面中显示这些特定的单词,但我不想将字符串存储在数据库中,以防将来需要更改它们(或国际化,或其他)。

显而易见的选择是为这些模型中的每一个定义模型,但这似乎会在维护模型、确保我为每个模型编写环境之间的迁移等方面带来大量开销,这看起来像很多开销。

另一种选择是将其存储为整数,然后创建一个“枚举”类型的类来存储这些值的翻译 - 这可能会很好,但我担心我会丢失关联和其他我从 ActiveRecord 模型中获得的方便的东西。

对处理这种情况的最佳方法有什么建议吗?

【问题讨论】:

    标签: ruby-on-rails


    【解决方案1】:

    查看我一直在研究的名为 classy_enum 的红宝石宝石。我很确定它完全符合您的要求。自述文件有一些示例用法,但前提是它允许您将多个枚举成员定义为可以具有不同属性的类。

    【讨论】:

    • @elsurudo 谢谢!自从我第一次发布这篇文章以来,它已经走了很长一段路,如果你最终使用它,我会很乐意提供反馈。
    • @Beerlington 我终于找到了提出问题的正确方法,这样我就可以找到你的宝石了;这是一个优雅、简单、强大的解决方案,解决了我在许多 Rails 项目中解决和重新解决的问题。我强烈推荐给其他人!
    【解决方案2】:

    在数据库中定义一个varcharENUM并验证模型中的字段:

    validates_inclusion_of :status, :in => %w(Defining Executed Completed)
    

    Rails 会将其视为字符串字段,但仍会验证值是什么。

    如果你真的需要抽象状态字段的文本,你可以把它保存为一个整数:

    class Foo < ActiveRecord::Base
      STATUS_DESCRIPTIONS = %w(Defining Executed Completed)
    
      def status
        STATUS_DESCRIPTIONS[ read_attribute(:status) ]
      end
    end
    

    如果它变得比这更复杂,你应该试试@Beerlington's gem。

    【讨论】:

    • 这种方式的问题在于,您只会得到一堆字符串,它们无法告诉您每个状态的含义。您仍然需要向应用程序添加逻辑以处理每个状态的行为。到那时,您不妨使用 gem。
    • @Beerlington 是的,这取决于业务逻辑的复杂程度。我们没有足够的信息来判断这一点,所以我建议使用最简单的方法。对于更复杂的场景,我认为你的 gem 会很好地工作。
    • Beerlington 是对的,我的情况可能会变得更复杂一些,但这仍然值得一票,因为如果不存在复杂性,这是一个非常好的解决方案,应该考虑。跨度>
    【解决方案3】:

    当我遇到enumerize gem 时,我正在寻找类似的解决方案。我喜欢它干净简单的 DSL。

    如果您的状态包含大量特定于状态的知识,那么 scaney 建议的状态机生成器可能是一个好主意。另一种选择是使用旧的state patternstate_pattern gem

    【讨论】:

      【解决方案4】:

      听起来你可能想要一个 state_machine,见这里: https://github.com/pluginaweek/state_machine

      【讨论】:

        【解决方案5】:

        把它放在一个模块中并混合到模型中怎么样:

        module StatusCodes
          DEFINING = 1
          EXECUTING = 2
          COMPLETED = 3
        
          def status
            return "" unless self[:status] # handle nil
            const_lookup = self[:status] - 1 # index to module constants
            StatusCodes.constants[const_lookup].to_s.downcase.camelcase # note: needs Ruby 1.9
          end
        end
        
        class MyModel < ActiveRecord::Base
          include StatusCodes
        end
        

        现在向模型添加一个整数 status 列,您可以像这样分配:

        m = MyModel.new(:status=>StatusCodes::DEFINING)
        

        并检索一个字符串:

        m.status # "Defining"
        

        【讨论】:

          【解决方案6】:

          为了完整起见,Rails 从 4.1 开始就有一个 Enum 类。

          【讨论】:

            【解决方案7】:

            与其他出色的选项一起,如果您选择概述的最后一个选项,则可以使用它:

            http://github.com/jasondew/coded_options

            (曾经和 Jason 一起工作,我们在几个 Rails 应用程序中使用了它的前身,尤其是当用户从选择标签中选择选项时)

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2017-09-17
              • 2019-05-09
              • 1970-01-01
              • 2014-06-18
              • 1970-01-01
              • 1970-01-01
              • 2021-09-28
              • 1970-01-01
              相关资源
              最近更新 更多