繁体   English   中英

如何在 rails 中指定和验证枚举?

[英]How do i specify and validate an enum in rails?

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

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

现在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?#maybe? ),以及使用属性 setter 方法(即: #yes! #no!#maybe!#maybe! )。

关于枚举的 Rails 文档

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

class Attend < ActiveRecord::Base

  STATUS_OPTIONS = %w(yes no maybe)

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

end

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

这就是我在 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}

在 Rails 文档中查看更多信息

您可以使用字符串列作为状态,然后使用:inclusion选项进行validates以确保您只获得您期望的内容:

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

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

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 }

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

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

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

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

出席.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

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

参加_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

要定义动态行为,您可以使用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

您可以使用rescue_from ::ArgumentError

rescue_from ::ArgumentError do |_exception|
  render json: { message: _exception.message }, status: :bad_request
end

想放置另一个解决方案。

#lib/lib_enums.rb
module LibEnums
  extend ActiveSupport::Concern

  included do
        validate do
        self.class::ENUMS.each do |e|
          if instance_variable_get("@not_valid_#{e}")
            errors.add(e.to_sym, "must be #{self.class.send("#{e}s").keys.join(' or ')}")
          end
        end
      end

        self::ENUMS.each do |e| 
          self.define_method("#{e}=") do |value|
            if !self.class.send("#{e}s").keys.include?(value)
              instance_variable_set("@not_valid_#{e}", true)
            else
              super value
            end
          end
        end
    end
end
#app/models/account.rb
require 'lib_enums'
class Account < ApplicationRecord
  ENUMS = %w(state kind meta_mode meta_margin_mode)
  include LibEnums
end

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM