W doskonałym blogu Bryana Helmkampa o nazwie "7 Patterns to Refactor Fat ActiveRecord Models", wspomina on o użyciu Form Objects
, aby oddzielić formularze wielowarstwowe i przestać używać accepts_nested_attributes_for
.na obiekcie ActiveModel, jak sprawdzić wyjątkowość?
Edycja: patrz below dla rozwiązania.
Mam prawie dokładnie duplikowane jego próbkę kodu, jak miałem ten sam problem do rozwiązania:
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
Jedną z rzeczy, różnych w moim kawałku kodu, jest to, że muszę zweryfikować unikalność nazwy konta (i e-mail użytkownika). Jednak ActiveModel::Validations
nie ma walidatora uniqueness
, ponieważ ma być wariantem bez bazy danych z obsługą ActiveRecord
.
Pomyślałem, istnieją trzy sposoby, aby sobie z tym poradzić:
- napisać własny sposób to sprawdzić (czuje się zbędny)
- Dołącz walidacji ActiveRecord :: :: UniquenessValidator (próbowałem, nie dostał go do pracy)
- Albo dodać ograniczenie w warstwie przechowywania danych
wolałbym użyć ostatni. Ale potem zastanawiam się, jak mogę to zaimplementować.
mógłby zrobić coś podobnego (metaprogramowanie, będę musiał zmodyfikować kilka innych obszarów):
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
Ale teraz mam dwie kontrole działa w mojej klasie, najpierw używam valid?
a następnie użyć instrukcja rescue
dla ograniczeń przechowywania danych.
Czy ktoś wie o dobrym sposobie rozwiązania tego problemu? Byłoby lepiej być może napisać do tego mój własny weryfikator (ale wtedy będę miał dwa zapytania do bazy danych, gdzie najlepiej wystarczyłoby).
Jeśli to może pomóc każdemu: w podobnej sytuacji, że to „ActiveRecord :: walidacji” zamiast „ActiveModel :: walidacji” - w ten sposób * validates_uniqueness_of * jest dostępny – Mat