[英]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.yes
、 Attend.no
、 Attend.maybe
用于每个检查器方法以查看是否设置了某些状态(即: #yes?
#no?
、 #maybe?
、 #maybe?
),以及使用属性 setter 方法(即: #yes!
#no!
、 #maybe!
、 #maybe!
)。
创建您想要的选项的全局可访问数组,然后验证状态列的值:
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}
您可以使用字符串列作为状态,然后使用: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.