【问题标题】:Rails 3 serialized attribute validation error: undefined method `read_attribute_for_validation' for nil:NilClassRails 3 序列化属性验证错误:nil:NilClass 的未定义方法“read_attribute_for_validation”
【发布时间】:2012-06-28 00:53:03
【问题描述】:

当尝试使用序列化属性(带有定义的类)时,Rails 很高兴,直到对象被保存。我的 ActiveRecord 模型和序列化对象(使用 ActiveModel::Validations)都有验证。作为我验证的一部分,父模型检查以确保序列化对象是valid?。我相信这是问题的核心,但我 (a) 不确定为什么会导致问题或 (b) 解决问题的最佳方法。

我已将问题简化为一个最小的 rails 项目:

代码

创建一个新的 rails 项目(版本 3.2.6)并使用我定义的 rails g model a data:text 创建一个 A 模型:

app/models/a.rb

class A < ActiveRecord::Base
  attr_accessible :data
  serialize :data, B

  validate :custom

  def custom
    errors.add :data, "whoopsies!" unless data.valid?
  end
end

app/models/b.rb

class B
  include ActiveModel::Validations
  attr_accessor :foo
  validates_presence_of :foo
end

test/unit/a_test.rb

require 'test_helper'

class ATest < ActiveSupport::TestCase
  test "weird failure" do
    a = A.new
    b = B.new
    b.foo = 'bar'
    a.data = b

    assert a.valid?
    assert b.valid?
    assert a.save

    assert a.valid? # -> throws exception
  end
end

异常

运行此测试会引发以下异常:

NoMethodError: undefined method `read_attribute_for_validation' for nil:NilClass
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activemodel-3.2.6/lib/active_model/errors.rb:254:in `block in add_on_blank'
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activemodel-3.2.6/lib/active_model/errors.rb:253:in `each'
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activemodel-3.2.6/lib/active_model/errors.rb:253:in `add_on_blank'
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activemodel-3.2.6/lib/active_model/validations/presence.rb:8:in `validate'
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activesupport-3.2.6/lib/active_support/callbacks.rb:310:in `_callback_before_7'
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activesupport-3.2.6/lib/active_support/callbacks.rb:407:in `_run__2107971919899649095__validate__2662006763039653414__callbacks'
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activesupport-3.2.6/lib/active_support/callbacks.rb:405:in `__run_callback'
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activesupport-3.2.6/lib/active_support/callbacks.rb:385:in `_run_validate_callbacks'
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activesupport-3.2.6/lib/active_support/callbacks.rb:81:in `run_callbacks'
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activemodel-3.2.6/lib/active_model/validations.rb:226:in `run_validations!'
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activemodel-3.2.6/lib/active_model/validations.rb:193:in `valid?'
    /Users/gbelote/tmp/serialize-fail/app/models/a.rb:8:in `custom'
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activesupport-3.2.6/lib/active_support/callbacks.rb:407:in `_run__3204678033069886840__validate__2662006763039653414__callbacks'
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activesupport-3.2.6/lib/active_support/callbacks.rb:405:in `__run_callback'
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activesupport-3.2.6/lib/active_support/callbacks.rb:385:in `_run_validate_callbacks'
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activesupport-3.2.6/lib/active_support/callbacks.rb:81:in `run_callbacks'
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activemodel-3.2.6/lib/active_model/validations.rb:226:in `run_validations!'
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activemodel-3.2.6/lib/active_model/validations/callbacks.rb:53:in `block in run_validations!'
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activesupport-3.2.6/lib/active_support/callbacks.rb:403:in `_run__3204678033069886840__validation__2662006763039653414__callbacks'
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activesupport-3.2.6/lib/active_support/callbacks.rb:405:in `__run_callback'
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activesupport-3.2.6/lib/active_support/callbacks.rb:385:in `_run_validation_callbacks'
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activesupport-3.2.6/lib/active_support/callbacks.rb:81:in `run_callbacks'
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activemodel-3.2.6/lib/active_model/validations/callbacks.rb:53:in `run_validations!'
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activemodel-3.2.6/lib/active_model/validations.rb:193:in `valid?'
    /Users/gbelote/.rvm/gems/ruby-1.9.2-p290@serialize-fail/gems/activerecord-3.2.6/lib/active_record/validations.rb:69:in `valid?'
    /Users/gbelote/tmp/serialize-fail/test/unit/a_test.rb:14:in `block in <class:ATest>'

另一个线索

在运行puts a.data.inspect 时,我在a.save 之前和之后得到不同的结果:

before: #<B:0x0000010327e710 @foo="bar", @validation_context=nil, @errors=#<ActiveModel::Errors:0x0000010321b7a0 @base=#<B:0x0000010327e710 ...>, @messages={}>>
after:  #<B:0x00000103197158 @foo="bar", @validation_context=nil, @errors=#<ActiveModel::Errors:0x000001031965f0 @base=nil, @messages={}>>

所以@errors 中的@base 为nil,这就是异常undefined methodread_attribute_for_validation 中提到的nil,用于nil:NilClass`。


有人知道发生了什么吗?这是 Rails 的错误吗?我做错了吗?

谢谢!

【问题讨论】:

    标签: ruby-on-rails-3 validation serialization ruby-on-rails-3.2


    【解决方案1】:

    升级到 ruby​​ 1.9.3-p194 解决了这个问题,我之前使用的是 1.9.2-p290。相关github问题:https://github.com/rails/rails/issues/6889

    【讨论】:

      猜你喜欢
      • 2012-12-27
      • 1970-01-01
      • 2016-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多