在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
。
我想有三種方式來處理這個問題:
- 寫我自己的方法來檢查這(感覺冗餘)
- 包含的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
但現在我已經在我的課上運行兩次檢查,第一次我用valid?
,然後我用一個rescue
聲明的數據存儲約束。
有誰知道處理這個問題的好方法?或許爲此寫一個自己的驗證器會更好一些(但是接下來我會對數據庫進行兩次查詢,理想情況下只需要一次)。
如果這可以幫助任何人:在類似的情況下,我包括代替「::加載ActiveModel驗證」「的ActiveRecord ::驗證」 - 這樣* validates_uniqueness_of *是可用 – Mat