na obiekcie ActiveModel, jak mogę sprawdzić unikalność?

W doskonałym blogu Bryana Helmkampa zatytułowanym „7 wzorów do modeli Refactor Fat ActiveRecord„, wspomina, używającForm Objects abstrahować od formularzy wielowarstwowych i przestać ich używaćaccepts_nested_attributes_for.

Edytuj: zobaczponiżej na rozwiązanie.

Prawie dokładnie zduplikowałem jego próbkę kodu, ponieważ 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 innych w moim fragmencie kodu jest to, że muszę zweryfikowaćwyjątkowość nazwy konta (i e-mail użytkownika). Jednak,ActiveModel::Validations nie mauniqueness walidator, ponieważ powinien być wariantem bez kopii zapasowej bazy danychActiveRecord.

Pomyślałem, że są na to trzy sposoby:

Napisz własną metodę, aby to sprawdzić (wydaje się zbędna)Dołącz ActiveRecord :: Validations :: UniquenessValidator (próbowałem tego, nie udało się go uruchomić)Lub dodaj ograniczenie w warstwie przechowywania danych

Wolałbym użyć ostatniego. Ale potem się zastanawiamw jaki sposób Zaimplementowałbym to.

Mógłbym zrobić coś takiego(metaprogramowanie, musiałbym zmodyfikować inne obszary):

  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 w mojej klasie, najpierw używamvalid? a potem używamrescue oświadczenie o ograniczeniach dotyczących przechowywania danych.

Czy ktoś zna dobry sposób na rozwiązanie tego problemu? Czy byłoby lepiej, gdyby napisał do tego mój własny walidator (ale wtedy miałbym dwa zapytania do bazy danych, gdzie najlepiej byłoby jedno).

questionAnswers(2)

yourAnswerToTheQuestion