在 Bryan Helmkamp 的优秀博文“7 Patterns to Refactor Fat ActiveRecord Models”中,他提到使用表单对象
来抽象多层表单并停止使用accepts_nested_attributes_for
。
编辑:参见below寻求解决方案。
我几乎完全复制了他的代码示例,因为我有同样的问题需要解决:
class Signup
include Virtus
extend ActiveModel::Naming
include ActiveModel::Conversion
include ActiveModel::Validations
attr_reader :user
attr_reader :account
attribute :name, String
attribute :account_name, String
attribute :email, String
validates :email, presence: true
validates :account_name,
uniqueness: { case_sensitive: false },
length: 3..40,
format: { with: /^([a-z0-9\-]+)$/i }
# Forms are never themselves persisted
def persisted?
false
end
def save
if valid?
persist!
true
else
false
end
end
private
def persist!
@account = Account.create!(name: account_name)
@user = @account.users.create!(name: name, email: email)
end
end
我的代码的不同之处之一是我需要验证帐户名(和用户电子邮件)的唯一性。但是,ActiveModel::Validations
没有唯一性
验证器,因为它应该是 ActiveRecord
的非数据库支持变体。
我认为可以通过三种方法来处理这个问题:
- 编写我自己的方法来检查这一点(感觉多余)
- 包含 ActiveRecord::Validations::UniquenessValidator(尝试过此操作,但没有成功)
- 或者在数据存储层添加约束
我更喜欢使用最后一个。但后来我一直想知道如何我将实现这个。
我可以做类似的事情(元编程,我需要修改一些其他区域):
def persist!
@account = Account.create!(name: account_name)
@user = @account.users.create!(name: name, email: email)
rescue ActiveRecord::RecordNotUnique
errors.add(:name, "not unique" )
false
end
但现在我的类中运行了两项检查,首先使用 valid?
,然后使用 rescue
语句来进行数据存储约束。
有谁知道解决这个问题的好方法吗?也许为此编写我自己的验证器会更好(但随后我会对数据库进行两次查询,理想情况下一个就足够了)。
最佳答案
如果这恰好是一次性要求,那么创建自定义验证器可能有点过分了。
简化的方法...
class Signup
(...)
validates :email, presence: true
validates :account_name, length: {within: 3..40}, format: { with: /^([a-z0-9\-]+)$/i }
# Call a private method to verify uniqueness
validate :account_name_is_unique
def persisted?
false
end
def save
if valid?
persist!
true
else
false
end
end
private
# Refactor as needed
def account_name_is_unique
if Account.where(name: account_name).exists?
errors.add(:account_name, 'Account name is taken')
end
end
def persist!
@account = Account.create!(name: account_name)
@user = @account.users.create!(name: name, email: email)
end
end
关于ruby-on-rails - 在 ActiveModel 对象上,如何检查唯一性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14670396/