2016-07-19 72 views
0

假設您有User has_many Books。每本書都有一個名字字段。如何在不保存Rails的情況下驗證字段的唯一性?

用戶輸入他們的書籍,並將其作爲一組名稱提交給應用程序。名稱陣列將取代任何現有書籍。

如果更新失敗,則不應更改書籍。

class Book 
    belongs_to :user 

    validates_uniquness_of :name, scope: [:user] 

如何檢查每本書的有效性而不保存?

例如:

['Rails Guide', 'Javascript for Dummies']將是有效的。

['Javascript for Dummies', 'Javascript for Dummies']將無效。

params[:books].each{| b | Book.new(b).valid? }將無法​​正常工作,因爲該書必須保存以獲得唯一性。

Mongoid

回答

1

您可以使用Active Record Transaction。開始交易,請致電save,如果失敗,則整個交易將被回滾。例如:

Book.transaction do 
    params[:books].each{ |b| Book.new(b).save! } 
end 

如果存在異常,則會中止整個事務。你應該通過捕獲ActiveRecord::RecordInvalid來處理這個案例。

+0

您還需要數據庫中的唯一性約束,然後您還需要捕獲「ActiveRecord :: RecordNotUnique」。 –

+0

這是一個很好的方式,但Mongo沒有交易。 –

1

您可以使用Array#map將書籍屬性數組轉換爲書名數組。然後使用Array#uniq從書本名稱的數組刪除重複項,然後檢查結果數組具有相同大小的書原數組屬性:

are_books_uniq = params[:books].map{|b| b[:name]}.uniq.size == params[:books].size 

這樣您就可以執行檢查,而不觸及數據庫。但爲了安全起見,您應該將所有書籍保存在交易中(參見@ Aaron的answer)。

+0

我不喜歡這樣做,因爲它重複驗證邏輯。 –

1

事實證明,這比我想象的複雜得多。

我想出了貌似解決方案:

def update params 
    names = params.delete(:books) 

    new_books = names.map{| title | Book.new(name:name)} 
    validate_books_for new_books 

    return false if errors.present? 
    return false unless super(params) 

    self.books = new_books 

    self 
    end 

大部分的複雜性來自於2個模型的耦合。我可以看到爲什麼模型耦合不是一個好主意。也許更好的設計是將書籍存儲爲數組。

相關問題