2017-01-10 64 views
1

一般來說,我想批量驗證一堆對象,我需要保存它們來執行唯一性驗證。然後,我回滾需要保存的唯一性驗證對象。提高ActiveRecord ::回滾和丟失嵌套的屬性值

這是批量導入用戶界面所需要的,我希望在用戶可以選擇持久存儲數據之前通知用戶有關其數據中的問題。

該方法似乎失敗,因爲該對象在第二次保存時失去其嵌套屬性。因此,第二次保存對象時,MySQL/SQlite會正確地告訴我該列爲空。

下面是一個例子:

ActiveRecord::Schema.define do 
    create_table :posts, force: true do |t| 
    t.string :title 
    end 

    create_table :comments, force: true do |t| 
    t.text :body, null: false 
    t.integer :post_id 
    end 
end 

class Post < ActiveRecord::Base 
    has_many :comments 
    validates :title, uniqueness: true 
    accepts_nested_attributes_for :comments 
end 

class Comment < ActiveRecord::Base 
    belongs_to :post 
end 

posts = [Post.new(title: "Title", comments_attributes: [{ body: "Comment" }])] 

ActiveRecord::Base.transaction do 
    posts.each do |p| 
    p.save # This saves fine 
    # Collecting validation errors here for presentation purposes 
    end 
    raise ActiveRecord::Rollback 
end 

# Now the comment attributes seem to be gone and 
# Mysql is raising an error because the 'body' column is null 
posts.each { |p| p.save } 

我有一個完全可運行測試用例這裏:https://gist.github.com/phansch/ab172e4b8cadf24f1e6508a0555e465c

有一些解決這個辦法嗎?我想我的問題歸結爲必須執行唯一性驗證,以在用戶決定繼續並確實堅持更改之前告訴用戶重複。

回答

0

您不需要保存並回滾Post記錄以驗證唯一性。您可以直接撥打post.valid?,所有驗證(包括唯一性驗證)都將運行。

而不是

ActiveRecord::Base.transaction do 
    posts.each do |p| 
    p.save # This saves fine 
    # Collecting validation errors here for presentation purposes 
    end 
    raise ActiveRecord::Rollback 
end 

只是做

posts.each(&:valid?) 

我只是測試它,它看起來像嵌套的記錄是通過這種方式影響。

+0

不幸的是,唯一性驗證只會比較新記錄和已經保存的記錄。請參閱http://guides.rubyonrails.org/active_record_validations.html#uniqueness。所以當我有兩個標題相同的未保存文章數組時,它不會告訴我,因爲它們都沒有被保留。 –

+0

啊,我現在明白了。個人確認取決於收集的其餘部分。這使得這有點困難。 :/ AR只支持單行插入...我看到的唯一好選擇是在AR之外編寫一些自定義檢查來檢查整個帖子數組。唯一需要檢查的是,在運行posts.each(&:valid?)之前,所有標題都是唯一的。無論如何,我會阻止通過AR事務進行驗證。如果你感覺冒險,你也可以檢查一些大容量導入寶石,如activerecord-import,看看他們是否支持這樣的東西。 – Glyoko