【问题标题】:How do i specify and validate an enum in rails?如何在 rails 中指定和验证枚举?
【发布时间】:2011-12-30 02:58:49
【问题描述】:

我目前有一个模型参加,它将有一个状态列,而这个状态列将只有几个值。 STATUS_OPTIONS = {:yes, :no, :maybe}

1) 我不确定如何在用户插入出席之前验证这一点?基本上是java中的枚举,但我怎么能在rails中做到这一点?

【问题讨论】:

  • mu 和 mike 的答案很好 - 另请参阅 stackoverflow.com/q/265725/887124 ,它对类似问题给出了一些略有不同的答案。
  • 是的,我实际上使用了与 Bob 提供的解决方案更相似的东西:gist

标签: ruby-on-rails validation activerecord


【解决方案1】:

现在Rails 4.1 包含枚举,您可以执行以下操作:

class Attend < ActiveRecord::Base
    enum size: [:yes, :no, :maybe]
    # also can use the %i() syntax for an array of symbols:
    # %i(yes no maybe)
    validates :size, inclusion: { in: sizes.keys }
end

然后为您提供一个范围(即:Attend.yesAttend.noAttend.maybe),以查看是否设置了某些状态(即:#yes?#no?#maybe? ),以及属性设置方法(即:#yes!#no!#maybe!)。

Rails Docs on enums

【讨论】:

  • 从我正在阅读的内容来看,当前的枚举实现是用于内部值,而不是用于向用户公开问题(我认为这是一种耻辱)。我从 2 月 14 日的以下线程中得到这个。github.com/rails/rails/issues/13971
  • 请注意,您必须在验证行之前定义枚举。
【解决方案2】:

创建一个您想要的选项的全局可访问数组,然后验证您的状态列的值:

class Attend < ActiveRecord::Base

  STATUS_OPTIONS = %w(yes no maybe)

  validates :status, :inclusion => {:in => STATUS_OPTIONS}

end

然后您可以通过Attend::STATUS_OPTIONS 访问可能的状态

【讨论】:

  • Pre Rails 4.1 这很好。在 Rails 4.1+ 中使用内置枚举:edgeguides.rubyonrails.org/…
  • 在 Rails 4.1 中使用“本机”枚举与在 postgresql 中使用真正的本机枚举具有相同的缺点。您需要注意实际顺序,一旦创建枚举就不能轻易修改等。此外,使用“本机”rails 枚举,这是一个损坏的功能,因为一方面您将它们作为刺来编写和读取,但在另一方面,您需要将它们作为数字进行查询。至少使用 postgresql 的枚举,数据库外的所有内容都会看到字符串。
  • 在挣扎了一个小时试图让 enum 工作之后,这个解决方案更有趣,并且没有缺点 - 不能对 Enum 说同样的话。
  • 使用enum 会使数据库不那么可读,您应该咨询您的模型以确定这个3 值在数据库中的含义。所以,我认为this one 是一个更好的答案。毕竟,你不可能白白拥有这么多的名声:D
【解决方案3】:

这就是我在 Rails 4 项目中实现的方式。

class Attend < ActiveRecord::Base
    enum size: [:yes, :no, :maybe]
    validates :size, inclusion: { in: Attend.sizes.keys }
end

Attend.sizes 为您提供映射。

Attend.sizes # {"yes" => 0, "no" => 1, "maybe" => 2}

See more in Rails doc

【讨论】:

  • this one 的注释基本相同,但这不起作用,因为枚举属性将在调用验证之前对无效值抛出 InvalidArgument 异常。更多信息在这里:github.com/rails/rails/issues/13971
  • @Koen。是的,我尝试了这个解决方案并最终得到了ArgumentError
【解决方案4】:

您可以使用字符串列作为状态,然后使用:inclusion option for validates 来确保您只得到您所期望的:

class Attend < ActiveRecord::Base
    validates :size, :inclusion => { :in => %w{yes no maybe} }
    #...
end

【讨论】:

    【解决方案5】:

    我们已经开始做的是在一个数组中定义我们的枚举项,然后使用该数组来指定枚举、验证以及在应用程序中使用值。

    STATUS_OPTIONS = [:yes, :no, :maybe]
    enum status_option: STATUS_OPTIONS
    validates :status_option, inclusion: { in: STATUS_OPTIONS.map(&:to_s) }
    

    这样您以后也可以使用 STATUS_OPTIONS,例如创建下拉列表。如果你想向用户公开你的值,你总是可以像这样映射:

    STATUS_OPTIONS.map {|s| s.to_s.titleize }
    

    【讨论】:

    【解决方案6】:

    对于 ActiveModels 中的枚举,您可以使用这个 gem Enumerize

    【讨论】:

      【解决方案7】:

      经过一番查找,我找不到模型中的单线来帮助它发生。到目前为止,Rails 提供了 Enums,但还没有一种全面的方法来验证无效值。

      所以,我选择了复合解决方案:在控制器中添加验证,然后设置 strong_params,然后检查模型。

      所以,在模型中,我将创建一个属性和一个自定义验证:

      attend.rb

      enum :status => { your set of values }
      attr_accessor :invalid_status
      
      validate :valid_status
      #...
      private
          def valid_status
              if self.invalid_status == true
                  errors.add(:status, "is not valid")
              end
          end
      

      另外,我会检查无效输入的参数并将结果(如有必要)发送到模型,因此将向对象添加错误,从而使其无效

      attends_controller.rb

      private
          def attend_params
              #modify strong_params to include the additional check
              if params[:attend][:status].in?(Attend.statuses.keys << nil) # to also allow nil input
                  # Leave this as it was before the check
                  params.require(:attend).permit(....) 
              else
                  params[:attend][:invalid_status] = true
                  # remove the 'status' attribute to avoid the exception and
                  # inject the attribute to the params to force invalid instance
                  params.require(:attend).permit(...., :invalid_status)
             end
          end
      

      【讨论】:

        【解决方案8】:

        要定义动态行为,您可以使用in: :method_name 表示法:

        class Attend < ActiveRecord::Base
          enum status: [:yes, :no, :maybe]
          validates :status, inclusion: {in: :allowed_statuses}
        
          private
        
          # restricts status to be changed from :no to :yes
          def allowed_statuses
            min_status = Attend.statuses[status_was]
            Attend.statuses.select { |_, v| v >= min_status }.keys
          end
        end
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-10-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-07-03
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多