В Bryan Helmkamp отличная запись в блоге под названием " 7 шаблонов для рефакторинга Fat ActiveRecord Models", он упоминает использование 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
для ограничений хранения данных.
Кто-нибудь знает хороший способ справиться с этой проблемой? Было бы лучше, возможно, написать мой собственный валидатор для этого (но тогда у меня было бы два запроса к базе данных, где в идеале было бы достаточно).