на объекте ActiveModel, как проверить уникальность?
В отличном посте Брайана Хелмкампа под названием "7 шаблонов для рефакторинга жирных моделей ActiveRecord«Он упоминает, используяForm Objects
абстрагировать многослойные формы и прекратить использованиеaccepts_nested_attributes_for
.
Изменить: см.ниже для решения.
Я почти точно продублировал его пример кода, так как мне пришлось решить ту же проблему:
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
не имеетuniqueness
валидатор, так как он должен быть вариантом базы данных без базы данных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
оператор для ограничений хранения данных.
Кто-нибудь знает хороший способ справиться с этой проблемой? Было бы лучше, возможно, написать свой собственный валидатор для этого (но тогда у меня будет два запроса к базе данных, где в идеале будет достаточно одного).