一般的に、オブジェクトの束を一括して検証しようとしており、一意性検証を実行するためにそれらを保存する必要があります。次に、一意性検証のために保存する必要のあるオブジェクトをロールバックします。ActiveRecord :: Rollbackを生成し、結果としてネストされた属性値を破棄します。
これは、データを永続化するオプションを使用する前に、データの問題についてユーザーに通知したいバッチインポートUIに必要です。
2回目の保存時にオブジェクトのネストされた属性が失われているため、アプローチが失敗したようです。だから、オブジェクトを2度保存すると、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
はこの周りのいくつかの方法はありますか?私の問題は、ユーザーが前進して実際に変更を維持することを決定する前に、重複の検証を実行して重複についてユーザーに伝えなければならないことになります。
残念ながら、一意性検証では、新しいレコードと、すでに永続化されているものとのみ比較されます。 http://guides.rubyonrails.org/active_record_validations.html#uniquenessを参照してください。だから私は同じタイトルを持っている2つの未保存の投稿の配列を持っているとき、それは永続化されていないので、私には言いません。 –
ああ、私は今理解しています。個々のバリデーションは、コレクションの残りの部分を条件にしています。これは少し難しくなります。 :/ ARは単一行の挿入だけをサポートしています...私が見る唯一の良いオプションは、ARの外にいくつかのカスタムチェックを書いて、ポスト配列全体をチェックすることです。ここでチェックするのは、posts.each(&:valid?)を実行する前にすべてのタイトルが一意であることだけです。いずれにしても、私はARトランザクションを通した検証を妨げるでしょう。あなたが冒険を感じているなら、activerecord-importのような大量インポートの宝石をチェックして、そういうものをサポートしているかどうか確認することもできます。 – Glyoko