在nested_attributes中传递的Rails无效id会导致未定义的方法`属性'为零:NilClass'

时间:2014-06-09 12:32:04

标签: ruby-on-rails activerecord

我正在实施一个以模型为特色的Rails应用程序:

class Document < ActiveRecord::Base
  has_many :categorisations
  has_many :categories, through: :categorisations

  accepts_nested_attributes_for :categorisations
end

class Category < ActiveRecord::Base
  has_many :categorisations
  has_many :documents, through: :categorisations
end

class Categorisation < ActiveRecord::Base
  belongs_to :document
  belongs_to :category

  validates_presence_of :document
  validates_presence_of :category

  validates_uniqueness_of :category, scope: :document
end

accepts_nested_attributes_forDocument的存在允许在文档创建时将类别附加到文档。这通常可以正常工作,除了通过嵌套属性传入无效的category-id(不存在类别的类别)的情况。在这种情况下:

document = Document.new({
  # .. attributes ..,
  categorisations_attributes: {
    '0' => {
      # .. more attributes ..,
      category_id: some_invalid_id
    }
  }
})

# Ouch, this results in 'NoMethodError: undefined method `attributes' for nil:NilClass'
document.valid?

不出所料,我在尝试document.save时遇到了同样的错误。此时,看起来我可以通过检查document.categorisations.first.category.nil?之类的内容来检测并抢占这一点。然而,这似乎不太理想,因为它不符合通常的Rails验证实践,我不能遵循document.save检测无效性的共同模式(通过false返回值)。

我是否缺少一些Rails最佳实践/更好的方法来布置我的模型以减轻这种情况?

[修改:这里是document.valid?]

案例的堆栈跟踪
activerecord-4.0.2/lib/active_record/validations/uniqueness.rb:56:in `build_relation'
activerecord-4.0.2/lib/active_record/validations/uniqueness.rb:22:in `validate_each'
activemodel-4.0.2/lib/active_model/validator.rb:153:in `block in validate'
activemodel-4.0.2/lib/active_model/validator.rb:150:in `each'
activemodel-4.0.2/lib/active_model/validator.rb:150:in `validate'
activesupport-4.0.2/lib/active_support/callbacks.rb:283:in `_callback_before_29'
activesupport-4.0.2/lib/active_support/callbacks.rb:407:in `_run__1039810079386051889__validate__callbacks'
activesupport-4.0.2/lib/active_support/callbacks.rb:80:in `run_callbacks'
activemodel-4.0.2/lib/active_model/validations.rb:373:in `run_validations!'
activemodel-4.0.2/lib/active_model/validations/callbacks.rb:106:in `block in run_validations!'
activesupport-4.0.2/lib/active_support/callbacks.rb:373:in `_run__1039810079386051889__validation__callbacks'
activesupport-4.0.2/lib/active_support/callbacks.rb:80:in `run_callbacks'
activemodel-4.0.2/lib/active_model/validations/callbacks.rb:106:in `run_validations!'
activemodel-4.0.2/lib/active_model/validations.rb:314:in `valid?'
activerecord-4.0.2/lib/active_record/validations.rb:70:in `valid?'
activerecord-4.0.2/lib/active_record/autosave_association.rb:304:in `association_valid?'
activerecord-4.0.2/lib/active_record/autosave_association.rb:293:in `block in validate_collection_association'
activerecord-4.0.2/lib/active_record/autosave_association.rb:293:in `each'
activerecord-4.0.2/lib/active_record/autosave_association.rb:293:in `validate_collection_association'
activerecord-4.0.2/lib/active_record/autosave_association.rb:207:in `block in add_autosave_association_callbacks'
activerecord-4.0.2/lib/active_record/autosave_association.rb:153:in `instance_eval'
activerecord-4.0.2/lib/active_record/autosave_association.rb:153:in `block in define_non_cyclic_method'
activesupport-4.0.2/lib/active_support/callbacks.rb:397:in `_run__779968926416857275__validate__callbacks'
activesupport-4.0.2/lib/active_support/callbacks.rb:80:in `run_callbacks'
activemodel-4.0.2/lib/active_model/validations.rb:373:in `run_validations!'
activemodel-4.0.2/lib/active_model/validations/callbacks.rb:106:in `block in run_validations!'
activesupport-4.0.2/lib/active_support/callbacks.rb:383:in `_run__779968926416857275__validation__callbacks'
activesupport-4.0.2/lib/active_support/callbacks.rb:80:in `run_callbacks'
activemodel-4.0.2/lib/active_model/validations/callbacks.rb:106:in `run_validations!'
activemodel-4.0.2/lib/active_model/validations.rb:314:in `valid?'
activerecord-4.0.2/lib/active_record/validations.rb:70:in `valid?'

[编辑2 :]

我更新了问题,以在validates_uniqueness_of :category, scope: :document模型中包含Categorisation约束。 删除它可以消除Nil错误,从而导致更加理智,验证错误和分类类别不能为空白&#39;代替。但是,验证到位后问题仍然存在。

1 个答案:

答案 0 :(得分:0)

我不确定,如果您尝试使用association而不仅仅是association_id,验证的工作原理如何,但您可以尝试使用validates_each代替validates_presence_of Categorisation模型中的验证:

validates_each :category_id do |record, attr, value|
  unless Category.exists?(id: value)
    record.errors.add(attr, "does not exist")
  end
end