多个Rails模型中的性别验证

时间:2010-12-08 01:33:16

标签: ruby-on-rails data-modeling

嘿所有 - 这个问题具体是关于gender验证,但是我有兴趣听听你们是如何处理类似情况的更大的集合(例如国家/地区选择)。

我正在开发一个让运动员注册各种活动的系统,目前正在进行良好的性别验证。我的问题是,在许多不同模型上运行相同验证的最佳,最干的方式是什么?

假设我要验证EventUser的性别属性。我可以为validates_each创建一个帮助程序,在更新gender属性之前检查包含在[“male”,“female”]的非常短的数组中的值。但是,如果我想在form_for块中访问同一性别数组,比如作为collection_select的输入,该怎么办?

我让它适用于一个模型 - 我在GENDERS中声明了一个Event常量,并且有一个短类方法

def self.genders
    GENDERS
end

表格访问。但是,如果需要访问多个模型,我应该在哪里存储数组?

编辑:一个想法是在应用程序控制器中使用类方法。关于这种方法的合适程度的任何想法都会很棒。

4 个答案:

答案 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