Ruby on rails 通过关联获取ActiveRecord::RecordInvalid错误与\u多个;联接表上的验证问题

Ruby on rails 通过关联获取ActiveRecord::RecordInvalid错误与\u多个;联接表上的验证问题,ruby-on-rails,ruby,ruby-on-rails-3,activerecord,has-many-through,Ruby On Rails,Ruby,Ruby On Rails 3,Activerecord,Has Many Through,我有三个类似的关联模型: class Product < ActiveRecord::Base belongs_to :user has_many :descriptions, { dependent: :destroy, before_add: [:add_user_id_to_description, :validate_description] } has_many :documents, through: :descriptions # ...

我有三个类似的关联模型:

class Product < ActiveRecord::Base
  belongs_to :user
  has_many :descriptions, {
    dependent: :destroy,
    before_add: [:add_user_id_to_description, :validate_description]
  }
  has_many :documents, through: :descriptions

  # ...

  def validate_description(d)
    unless d.valid?
      d.errors[:user_id].each do |err|
        self.errors.add(:base, "Doc error: #{err}")
      end
    end
  end
end

class Document < ActiveRecord::Base
  belongs_to :user
  has_many :descriptions, {
    dependent: :destroy,
    before_add: [:add_user_id_to_description, :validate_description]
  }
  has_many :products, through: :descriptions
end

class Description < ActiveRecord::Base
  belongs_to :user
  belongs_to :product
  belongs_to :document
end
description
验证失败,然后我得到
false
doc
上的相应错误。这正是我想要的

但是,如果
doc
已经存在,例如:

doc = user.documents.first
doc.update_attributes(:product_ids => [1,2])
description
验证失败,则出现
ActiveRecord::RecordInvalid
错误

我确切地知道为什么会发生这种情况——调用
save中的
insert\u record
方法内部,这会传播错误。它会提前退出,跳过此调用以获取新记录

有什么方法可以设置我的模型来防止这种
保存?或者我是被迫从错误中解救出来的

编辑

我试过下面卡洛斯·德鲁描述的设置;我还尝试了设置
验证\u关联的:描述
,并将
反向的::whatever
添加到
中有许多:描述
选项散列。我还尝试在
产品
文档
模型上设置
验证前
回调,但显然关联回调首先运行(?)。每次尝试似乎都会产生完全相同的错误信息

我正在从下面的控制台粘贴错误跟踪

Document Load (1.8ms)  SELECT "documents".* FROM "documents" WHERE "documents"."user_id" = 19 ORDER BY "documents"."id" DESC LIMIT 1
   (1.0ms)  BEGIN
  Product Load (41.7ms)  SELECT "products".* FROM "products" WHERE "products"."id" = $1 LIMIT 1  [["id", 3640]]
  Product Load (4.1ms)  SELECT "products".* FROM "products" INNER JOIN "descriptions" ON "products"."id" = "descriptions"."product_id" WHERE "descriptions"."document_id" = 3552
  User Load (7.0ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 19 LIMIT 1
  Account Load (2.0ms)  SELECT "accounts".* FROM "accounts" WHERE "accounts"."user_id" = 19 LIMIT 1
   (0.9ms)  SELECT COUNT(*) FROM "descriptions" WHERE "descriptions"."user_id" = 19
   (1.2ms)  ROLLBACK
ActiveRecord::RecordInvalid: Validation failed: User You have reached limit of 1
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/validations.rb:56:in `save!'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/attribute_methods/dirty.rb:33:in `save!'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/transactions.rb:264:in `block in save!'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/transactions.rb:313:in `block in with_transaction_returning_status'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/connection_adapters/abstract/database_statements.rb:192:in `transaction'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/transactions.rb:208:in `transaction'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/transactions.rb:311:in `with_transaction_returning_status'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/transactions.rb:264:in `save!'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/associations/has_many_through_association.rb:85:in `save_through_record'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/associations/has_many_through_association.rb:52:in `insert_record'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/associations/collection_association.rb:496:in `block (2 levels) in concat_records'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/associations/collection_association.rb:344:in `add_to_target'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/associations/collection_association.rb:495:in `block in concat_records'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/associations/collection_association.rb:493:in `each'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/associations/collection_association.rb:493:in `concat_records'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/associations/collection_association.rb:134:in `block in concat'
... 14 levels...
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/associations/builder/collection_association.rb:71:in `block in define_writers'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/attribute_assignment.rb:85:in `block in assign_attributes'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/attribute_assignment.rb:78:in `each'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/attribute_assignment.rb:78:in `assign_attributes'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/persistence.rb:216:in `block in update_attributes'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/transactions.rb:313:in `block in with_transaction_returning_status'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/connection_adapters/abstract/database_statements.rb:192:in `transaction'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/transactions.rb:208:in `transaction'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/transactions.rb:311:in `with_transaction_returning_status'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/persistence.rb:215:in `update_attributes'
    from (irb):2
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.13/lib/rails/commands/console.rb:47:in `start'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.13/lib/rails/commands/console.rb:8:in `start'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.13/lib/rails/commands.rb:41:in `<top (required)>'
    from script/rails:6:in `require'
    from script/rails:6:in `<main>'
Document Load(1.8ms)从“documents”中选择“documents”。*其中“documents”。“user_id”=19按“documents”排序。“id”描述限制1
(1.0毫秒)开始
产品负载(41.7ms)从“产品”中选择“产品”。*其中“产品”。“id”=1美元限额1[[“id”,3640]]
产品加载(4.1ms)选择“产品”。*从“产品”内部连接“产品”上的“说明”。“id”=“说明”。“产品id”中的“说明”。“文档id”=3552
用户加载(7.0ms)从“用户”中选择“用户”。*其中“用户”。“id”=19限制1
帐户加载(2.0ms)从“帐户”中选择“帐户”。*其中“帐户”。“用户id”=19限制1
(0.9ms)从“说明”中选择计数(*),其中“说明”。“用户id”=19
(1.2ms)回滚
ActiveRecord::RecordInvalid:验证失败:用户已达到1的限制
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/validations.rb:56:in'save!'
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active\u record/attribute\u methods/dirty.rb:33:in'save!'
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/transactions.rb:264:在“保存中的块”中
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active\u record/transactions.rb:313:in `块入,事务返回\u状态'
来自/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active\u record/connection\u adapters/abstract/database\u语句。rb:192:在“事务”中
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/transactions.rb:208:in“transaction”
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active\u record/transactions.rb:311:in`with\u transaction\u returning\u status'
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/transactions.rb:264:in'save!'
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active\u-record/associations/has\u-many\u-through\u-association.rb:85:in'save\u-through\u-record'
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active\u record/associations/has\u many\u-to\u-association.rb:52:in'insert\u-record'
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active\u record/associations/collection\u association.rb:496:concat\u records中的“块(2级)”中
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active\u record/associations/collection\u association.rb:344:“添加到目标”
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active\u record/associations/collection\u association.rb:495:in“concat\u记录中的块”
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active\u record/associations/collection\u association.rb:493:in'each'
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active\u record/associations/collection\u association.rb:493:in'concat\u records'
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active\u record/associations/collection\u association.rb:134:in'block in concat'
... 14级。。。
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active\u record/associations/builder/collection\u association.rb:71:“定义中的块”
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active\u record/attribute\u assignment.rb:85:在“分配属性中的块”中
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active\u record/attribute\u assignment.rb:78:in'each'
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active\u record/attribute\u assignment.rb:78:in“assign\u attributes”
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active\u record/persistence.rb:216:“更新中的块属性”
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active\u record/transactions.rb:313:in `块入,事务返回\u状态'
来自/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active\u record/connection\u adapters/abstract/database\u语句。rb:192:在“事务”中
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/transactions.rb:208:in“transaction”
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active\u record/transactions.rb:311:in`with\u transaction\u returning\u status'
from/usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active\u record/persistence.rb:215:in“update\u attributes”
Document Load (1.8ms)  SELECT "documents".* FROM "documents" WHERE "documents"."user_id" = 19 ORDER BY "documents"."id" DESC LIMIT 1
   (1.0ms)  BEGIN
  Product Load (41.7ms)  SELECT "products".* FROM "products" WHERE "products"."id" = $1 LIMIT 1  [["id", 3640]]
  Product Load (4.1ms)  SELECT "products".* FROM "products" INNER JOIN "descriptions" ON "products"."id" = "descriptions"."product_id" WHERE "descriptions"."document_id" = 3552
  User Load (7.0ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 19 LIMIT 1
  Account Load (2.0ms)  SELECT "accounts".* FROM "accounts" WHERE "accounts"."user_id" = 19 LIMIT 1
   (0.9ms)  SELECT COUNT(*) FROM "descriptions" WHERE "descriptions"."user_id" = 19
   (1.2ms)  ROLLBACK
ActiveRecord::RecordInvalid: Validation failed: User You have reached limit of 1
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/validations.rb:56:in `save!'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/attribute_methods/dirty.rb:33:in `save!'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/transactions.rb:264:in `block in save!'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/transactions.rb:313:in `block in with_transaction_returning_status'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/connection_adapters/abstract/database_statements.rb:192:in `transaction'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/transactions.rb:208:in `transaction'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/transactions.rb:311:in `with_transaction_returning_status'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/transactions.rb:264:in `save!'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/associations/has_many_through_association.rb:85:in `save_through_record'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/associations/has_many_through_association.rb:52:in `insert_record'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/associations/collection_association.rb:496:in `block (2 levels) in concat_records'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/associations/collection_association.rb:344:in `add_to_target'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/associations/collection_association.rb:495:in `block in concat_records'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/associations/collection_association.rb:493:in `each'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/associations/collection_association.rb:493:in `concat_records'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/associations/collection_association.rb:134:in `block in concat'
... 14 levels...
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/associations/builder/collection_association.rb:71:in `block in define_writers'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/attribute_assignment.rb:85:in `block in assign_attributes'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/attribute_assignment.rb:78:in `each'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/attribute_assignment.rb:78:in `assign_attributes'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/persistence.rb:216:in `block in update_attributes'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/transactions.rb:313:in `block in with_transaction_returning_status'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/connection_adapters/abstract/database_statements.rb:192:in `transaction'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/transactions.rb:208:in `transaction'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/transactions.rb:311:in `with_transaction_returning_status'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.13/lib/active_record/persistence.rb:215:in `update_attributes'
    from (irb):2
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.13/lib/rails/commands/console.rb:47:in `start'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.13/lib/rails/commands/console.rb:8:in `start'
    from /usr/local/rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.13/lib/rails/commands.rb:41:in `<top (required)>'
    from script/rails:6:in `require'
    from script/rails:6:in `<main>'