Bryan Helmkampの優れたブログ記事「7 Patterns to Refactor Fat ActiveRecord Models」では、Form Objects
を使用して、複数レイヤーのフォームを抽象化し、accepts_nested_attributes_for
の使用をやめるように言及しています。ActiveModelオブジェクトで、一意性をチェックするにはどうすればよいですか?
編集:解決策はbelowを参照してください。私は解決するために同じ問題を抱えていたよう
は、私はほぼ正確に、彼のコードサンプルを複製しました:コードの私の作品では異なるものの
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
の非データベースバッキングバリアントであるためです。私はこれを処理するための3つの方法があります考え出し
:
- は
- (冗長な感じ)これを確認するために自分自身のメソッドを書くのActiveRecord ::検証を含める:: 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
をしかし、今、私は、私のクラスで実行されている2つのチェックを持っている最初の私はvalid?
を使用して、私が使用してデータ記憶制約のためのrescue
ステートメント。
誰もがこの問題を処理する良い方法を知っていますか?おそらく私自身のバリデーターを書くのが良いでしょうか(しかし、データベースに2つのクエリがあり、理想的には1つあれば十分でしょう)。
これは誰を助けることができる場合は、次の似たような状況で、私は含める「のActiveRecord ::の検証」の代わりに「ActiveModel ::検証」 - このように* validates_uniqueness_of *ですavailable – Mat