Rails 4:使用表单对象时验证关联的ActiveRecord模型

时间:2015-05-17 17:55:59

标签: ruby validation ruby-on-rails-4

我使用基于ActiveModel的表单对象来处理应用程序的注册(注册)。 account课程摘录了useraccount(该帐户的主要用户)的信息。

但是,我发现我在user类中复制了signupsignup的验证逻辑。当我编写我的规范(使用rspec)时,我意识到这种重复可能表明我处理这个问题的方式存在问题。

有没有办法将account课程中的验证传递给usersignup模型而不重复?这样,验证将保留在这些模型中,我可以在signup类中引用/调用它。

以下是我所使用的class Signup include ActiveModel::Model # Scopes #---------------------------------------------------------------------- # NOOP # Macros #---------------------------------------------------------------------- attr_accessor :slug, :email, :password, :password_confirmation # Associations #---------------------------------------------------------------------- # NOOP # Validations #---------------------------------------------------------------------- validate :verify_unique_email validate :verify_unique_slug validates :email, presence: true, format: { with: /@/, message: "is invalid" } validates :password, presence: true, length: { minimum: 8 }, confirmation: true validates :password_confirmation, presence: true validates :slug, presence: true, format: { with: /\A[\w-]+\z/, message: "is invalid" }, exclusion: { in: %w[signup signups login] } # Methods #---------------------------------------------------------------------- def account @account ||= Account.new end def user @user ||= account.build_primary_user end def save account.active = true account.slug = slug user.email = email user.password = password user.password_confirmation = password_confirmation if valid? ActiveRecord::Base.transaction do account.save! user.save! end true else false end end def save! save end private def verify_unique_email if User.exists?(email: email) errors.add :email, "is invalid" end end def verify_unique_slug if Account.exists?(slug: slug) errors.add :slug, "has already been taken" end end end 类,但似乎是重复代码......

account

此处为class Account < ActiveRecord::Base has_one :primary_user, -> { where(primary: true) }, class_name: User has_many :users, dependent: :destroy validates :slug, uniqueness: true, presence: true, format: { with: /\A[\w-]+\z/, message: "is invalid" }, exclusion: { in: %w[signup signups login] } end 模型,请注意重复验证:

select company_id, 
       case when sum(approved_status='APPROVED') > 0 then 'APPROVED'
            when sum(approved_status='NOT') > 0 then 'NOT'
            else null
       end as `status`
from your_table
group by company_id

2 个答案:

答案 0 :(得分:1)

我喜欢你使用form object做的事情。 validates_associated :user, :account可能会有所帮助,但错误消息可能有些奇怪。相反,我可能会使用mixins for common validations

class Account < ActiveRecord::Base
  module Validations
    extend ActiveSupport::Concern
    included do
      validates :slug, presence: true
    end
  end
  include Validations
end

class Signup
  include ActiveModel::Model
  include Account::Validations
  extend Forwardable
  def_delegators :account, :slug
end

答案 1 :(得分:0)

最简单的方法是:

def valid?
  user.valid? && account.valid? && super
end

然后您可以摆脱重复的验证。

仅当您需要superUser之外的其他验证时才需要Account。这也会将错误添加到UserAccount对象中,这可能比Signup类更有用。