我使用基于ActiveModel的表单对象来处理应用程序的注册(注册)。 account
课程摘录了user
和account
(该帐户的主要用户)的信息。
但是,我发现我在user
类中复制了signup
和signup
的验证逻辑。当我编写我的规范(使用rspec)时,我意识到这种重复可能表明我处理这个问题的方式存在问题。
有没有办法将account
课程中的验证传递给user
和signup
模型而不重复?这样,验证将保留在这些模型中,我可以在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
答案 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
然后您可以摆脱重复的验证。
仅当您需要super
和User
之外的其他验证时才需要Account
。这也会将错误添加到User
和Account
对象中,这可能比Signup
类更有用。