Wie überprüfe ich die Eindeutigkeit eines ActiveModel-Objekts?
In Bryan Helmkamps ausgezeichnetem Blogpost mit dem Titel "7 Muster zur Refaktorisierung von Fat ActiveRecord-Modellen", erwähnt er mitForm Objects
um mehrschichtige Formulare zu abstrahieren und die Verwendung zu beendenaccepts_nested_attributes_for
.
Bearbeiten: sieheunten für eine Lösung.
Ich habe sein Codebeispiel fast genau dupliziert, da ich das gleiche Problem zu lösen hatte:
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
Eines der Dinge, die sich in meinem Code unterscheiden, ist, dass ich das validieren mussEinzigartigkeit des Kontonamens (und der Benutzer-E-Mail). Jedoch,ActiveModel::Validations
hat keineuniqueness
validator, da es sich um eine nicht datenbankgestützte Variante von handeln sollActiveRecord
.
Ich dachte mir, dass es drei Möglichkeiten gibt, damit umzugehen:
Schreiben Sie meine eigene Methode, um dies zu überprüfen (fühlt sich überflüssig an)Include ActiveRecord :: Validations :: UniquenessValidator (habe es versucht, habe es nicht zum Laufen gebracht)Oder fügen Sie die Einschränkung in die Datenspeicherebene einIch würde lieber den letzten verwenden. Aber dann wundere ich mich immer wiederWie Ich würde das umsetzen.
Ich könnte sowas machen(Metaprogrammierung, ich müsste einige andere Bereiche ändern):
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
Aber jetzt habe ich zwei Schecks in meiner Klasse, die ich zuerst benutzevalid?
und dann benutze ich arescue
Anweisung für die Datenspeicherungsbeschränkungen.
Kennt jemand einen guten Weg, um mit diesem Problem umzugehen? Wäre es besser, vielleicht meinen eigenen Validator dafür zu schreiben (aber dann hätte ich zwei Abfragen an die Datenbank, wo im Idealfall eine genug wäre).