ブライアンヘルムカンプの優れたブログ投稿「ファットActiveRecordモデルをリファクタリングするための7つのパターン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
私のコードの違いの1つは、アカウント名(およびユーザーの電子メール)の一意性を検証する必要があることです。ただし、データベースにバックアップされていないのバリアントであると想定されているためActiveModel::Validations
、バリデーターはありません。uniqueness
ActiveRecord
これを処理する方法は3つあると思いました。
- これをチェックするための独自のメソッドを作成します(冗長に感じます)
- 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
しかし、今ではクラスで2つのチェックを実行しています。最初に使用valid?
し、次にrescue
データストレージ制約のステートメントを使用します。
この問題を処理する良い方法を知っている人はいますか?このために独自のバリデーターを作成する方がよいでしょうか(ただし、データベースに対して2つのクエリがあり、理想的には1つで十分です)。