嘿所有 - 这个问题具体是关于gender
验证,但是我有兴趣听听你们是如何处理类似情况的更大的集合(例如国家/地区选择)。
我正在开发一个让运动员注册各种活动的系统,目前正在进行良好的性别验证。我的问题是,在许多不同模型上运行相同验证的最佳,最干的方式是什么?
假设我要验证Event
和User
的性别属性。我可以为validates_each
创建一个帮助程序,在更新gender
属性之前检查包含在[“male”,“female”]的非常短的数组中的值。但是,如果我想在form_for
块中访问同一性别数组,比如作为collection_select
的输入,该怎么办?
我让它适用于一个模型 - 我在GENDERS
中声明了一个Event
常量,并且有一个短类方法
def self.genders
GENDERS
end
表格访问。但是,如果需要访问多个模型,我应该在哪里存储数组?
编辑:一个想法是在应用程序控制器中使用类方法。关于这种方法的合适程度的任何想法都会很棒。
答案 0 :(得分:9)
这是我的解决方案。我喜欢使用标准的插件式库。我把它放在lib / acts_as_gendered中:
module ActsAsGendered
GENDERS = ['male', 'female']
def self.included(base)
base.extend(ActsAsGenderedMethods)
end
module ActsAsGenderedMethods
def acts_as_gendered
extend ClassMethods
include InstanceMethods
validates_inclusion_of :gender, :in => GENDERS
end
end
module ClassMethods
def is_gendered?
true
end
end
module InstanceMethods
def is_male
gender = 'male'
end
def is_female
gender = 'female'
end
def is_male?
gender == 'male'
end
def is_female?
gender == 'female'
end
end
end
是的,对于简单的性别来说可能有点过头了,但你可以看到所有部分的去处--GENDERS常量,acts_as_gendered
ActiveRecord钩子,然后包括类和实例方法以及验证。
然后,在config / initializers / gender.rb中:
require 'acts_as_gendered'
ActiveRecord::Base.send(:include, ActsAsGendered)
然后,对于大结局,模特:
class User < ActiveRecord::Base
acts_as_gendered
end
这种模式可能看起来过于复杂,但这就是大多数图书馆最终的结果:)
更新:要回答您的评论,我就是这样修改acts_as_gendered方法,以便在每个模型的基础上使验证成为可选项:
def acts_as_gendered options={}
config = {:allow_nil => false}
config.merge(options) if options.is_a?(Hash)
extend ClassMethods
include InstanceMethods
if config[:allow_nil]
validates_inclusion_of :gender, :in => (GENDERS + nil)
else
validates_inclusion_of :gender, :in => GENDERS
end
end
现在您可以在用户模型中调用它,如下所示:
class User < ActiveRecord::Base
acts_as_gendered :allow_nil => true
end
我本可以把它作为你传入的一个简单参数,但我喜欢传递散列的清晰度。它会让你在未来增加其他选择。
答案 1 :(得分:2)
通过将其存储在常量中,你有了正确的想法。我唯一要做的就是把它放在一个初始化器文件中,这样就不会像你的例子那样绑定任何特定的模型。如果您担心顶层的潜在名称冲突,可以将它放在lib目录中的模块中,并将模块仅包含在您打算使用它的位置。
答案 2 :(得分:1)
我同意将其置于常数中。我还将字符串本身放在常量中,因为(1)它们可以改变,(2)当在条件中使用时,如果你输入错误,系统会捕获。例如,在您的environment.rb中:
MALE = 'male'
FEMALE = 'female'
GENDERS = [MALE, FEMALE]
然后在你的代码中,你只能引用这些常量,例如:
def male?
return gender == MALE
end
答案 3 :(得分:-1)
我会写一个自定义验证插件(比如validates_gender
)。然后你会打电话:
class Event < ActiveRecord::Base
validates_gender :gender
end
抓取我的validates_as_email插件的副本并使用它,用您自己的逻辑替换value =~ EMAIL_ADDRESS_RE
。