【问题标题】:ActiveRecord::UnknownAttributeError after upgrade from Rails 3.2.7 to 3.2.21 and Ruby 1.9.3 to 2.0.0从 Rails 3.2.7 升级到 3.2.21 和 Ruby 1.9.3 到 2.0.0 后 ActiveRecord::UnknownAttributeError
【发布时间】:2015-01-21 01:23:38
【问题描述】:

我刚刚将一个旧应用从 Rails 3.2.7 升级到 3.2.21,从 Ruby 1.9.3 升级到 2.0.0,在试用该应用时出现以下错误:

Started PUT "/books/17" for 127.0.0.1 at 2015-01-20 16:15:10 -0800 
Processing by BooksController#update as HTML
  Parameters: {"utf8"=>"✓", 
  "authenticity_token"=>"mXizjcxG5Yq0BYG9vvvuqjW6O3/KhG6fUkoEeU6ORP8=", 
  "book"=>{"new_book_item_attributes"=>{"1421799301.062898"=>{"content_id"=>"16"}}}, 
  "commit"=>"Add selected content", "id"=>"17"} 

ActiveRecord::UnknownAttributeError (unknown attribute: new_book_item_attributes):
  app/controllers/books_controller.rb:70:in `block in update'
  app/controllers/books_controller.rb:69:in `update'

这是我的相关代码:

books_controller.rb:69

if @book.update_attributes(params[:book])

book.rb

class Book < ActiveRecord::Base

attr_accessible ... :new_book_item_attributes

def new_book_item_attributes=(attributes)
  attributes.each do |attribute|
    book_items.build(skip_over_time(attribute))
  end
end

我浏览了http://weblog.rubyonrails.org/releases/ 中的每个博客条目,从 Rails 3.2.8.rc1 已发布!Rails 3.2.21、4.0.12 和 4.1.8 已发布发布了,我没有发现任何可以解释这个问题的激烈的东西。无论如何,这是一个“补丁级”升级,所以我不希望有任何剧烈的变化。知道可能有什么问题吗?


更新

  • Rails 3.2.21 和 Ruby 1.9.3 不会出现此问题(它只会出现在 Ruby 2.0.0 上(不管 Rails 是什么(3.2.213.2.7))。

我将@xavier-shay标识的代码块修改如下:

  puts "-1- attributes: #{attributes.inspect}"

  attributes.each do |k, v|
    puts "-2- testing k: #{k}, v: #{v}"
    if k.include?("(")
      puts "-3- true to k.include?(\"(\")"
      multi_parameter_attributes << [ k, v ]
    elsif respond_to?("#{k}=")
      puts "-4- true to respond_to?(\"#{k}=\")"
      if v.is_a?(Hash)
        puts "-5- true to v.is_a?(Hash)"
        nested_parameter_attributes << [ k, v ]
      else
        puts "-6- else"
        send("#{k}=", v)
      end
    else
      puts "-7- UnknownAttributeError"
      raise(UnknownAttributeError, "unknown attribute: #{k}")
    end
  end

在 Ruby 2.0.0 和 Rails 3.2.21 上运行它会引发上述参数的异常:

-1- attributes: {"new_book_item_attributes"=>{"1421825320.571702"=>{"content_id"=>"8"}}}
-2- testing k: new_book_item_attributes, v: {"1421825320.571702"=>{"content_id"=>"8"}}
-7- UnknownAttributeError

...但是,在另一个控制器中,(显然使用不同的参数)没有问题:

-1- attributes: {"title"=>"test title", "subtitle"=>"test subtitle"}
-2- testing k: title, v: test title
-4- true to respond_to?("title=")
-6- else
-2- testing k: subtitle, v: test subtitle
-4- true to respond_to?("subtitle=")
-6- else

在 Ruby 1.9.3 和 Rails 3.2.21 上运行没有问题:

-1- attributes: {"new_book_item_attributes"=>{"1421828430.9315462"=>{"content_id"=>"8"}}}
-2- testing k: new_book_item_attributes, v: {"1421828430.9315462"=>{"content_id"=>"8"}}
-4- true to respond_to?("new_book_item_attributes=")
-5- true to v.is_a?(Hash)
-1- attributes: {"content_id"=>"8"}
-2- testing k: content_id, v: 8
-4- true to respond_to?("content_id=")
-6- else
-1- attributes: {"book_id"=>17}
-2- testing k: book_id, v: 17 
-4- true to respond_to?("book_id=")
-6- else

这个推论指向 Ruby,而不是 Rails。关于我应该如何进一步调试的任何想法?

【问题讨论】:

  • 发布错误发生的整个动作怎么样?
  • 如果为 new_book_item_attributes 添加一个空的 getter 会发生什么?
  • 感谢您的 cmets。我用我做的一些调试更新了我的问题。目前看来 Ruby 是问题所在——尽管我不确定如何继续调试。
  • 您的两个控制器的属性之间有两个区别:1)嵌套值-->应该没关系,因为它是问题的关键。 2)蛇案名v.单名;或...长名称与短名称。您可以尝试将虚拟属性的名称更改为x吗?
  • 我将虚拟属性更改为xxx,问题是相同的。再次感谢您的帮助。

标签: ruby-on-rails ruby activerecord ruby-1.9.3 ruby-2.0


【解决方案1】:

我怀疑这里缺少某些导致问题的上下文,因为从查看您提供的内容来看并不明显。

这里有一些关于如何追踪它的选项。

  • 找出 rails 中的哪些代码引发了这个异常。 Ruby 让这变得非常简单。您可以删除回溯消音器(可能在 config/initializers/backtrace_silencers.rb 中),或者您可以使用 grep 获取 UnknownAttributeError 的 Rails 源代码。事实证明,只有one place where this error is raised

    attributes.each do |k, v|
      if k.include?("(")
        multi_parameter_attributes << [ k, v ]
      elsif respond_to?("#{k}=")
        if v.is_a?(Hash)
          nested_parameter_attributes << [ k, v ]
        else
          send("#{k}=", v)
        end
      else
        raise(UnknownAttributeError, "unknown attribute: #{k}")
      end
    end
    

    因此,这表明您的模型没有正确响应方法名称。您可以在此处添加一些 puts 语句(使用 bundle show rails 查找磁盘上的位置)或在控制台中使用它来查看发生了什么。

  • 通过二分法准确找出哪个补丁版本导致了问题。也就是说,去 3.2.15 看看你有没有看到错误。隔离破坏它的版本后,您可以查看差异和/或更改日志以查看更改的内容。至少,缩小范围会帮助这里的其他人为您提供帮助。

  • 您能否进行最少的复制?您可以从模型中删除多少代码但仍会出现问题?您可以使用独立的 ActiveRecord 脚本重现该问题吗?即类似Active record in standalone Ruby

希望对你有帮助,告诉我你的进展如何!

【讨论】:

  • 非常感谢您详尽的回答 - 我很荣幸 回答了顺便说一句,因为我熟悉您的一些数据库工作.. :) 无论如何,我一分为二确定实际上是 Ruby 版本是罪魁祸首的方法。 (我碰巧最近也升级了 Ruby - 当我第一次发布我的问题时,我只是没想到要提及它。)因此我从 Ruby 2.0.0 降级到 1.9.3 并且问题消失了。请参阅我更新的问题 - 我不确定如何继续进一步调试。想法?
【解决方案2】:

我在这里看不出 ruby​​ 1.9.3 和 ruby​​ 2.0 之间有什么区别:

class Dog
  def new_book_item_attributes=()
  end
end

d = Dog.new

k = "new_book_item_attributes"

if d.respond_to?("#{k}=")
   p %Q{-4- true to respond_to?("#{k}=")}
end

注意:你不需要在 ruby​​ 中转义内部引号。

输出:

~/ruby_programs$ ruby -v
ruby 1.9.3p547 (2014-05-14 revision 45962) [x86_64-darwin10.8.0]

~/ruby_programs$ ruby 1.rb 
"-4- true to respond_to?(\"new_book_item_attributes=\")"

~/ruby_programs$ rvm use 2.0.0
Using /Users/7stud/.rvm/gems/ruby-2.0.0-p481

~/ruby_programs$ ruby -v
ruby 2.0.0p481 (2014-05-08 revision 45883) [x86_64-darwin10.8.0]

~/ruby_programs$ ruby 1.rb 
"-4- true to respond_to?(\"new_book_item_attributes=\")"

~/ruby_programs$ 

您能否重新运行测试并使用 p 而不是 puts 来输出字符串?

我在两个版本的 ruby​​ 下得到相同的输出:

class Dog
  def new_book_item_attributes=()
  end
end

d = Dog.new

attributes = {"new_book_item_attributes"=>{"1421825320.571702"=>{"content_id"=>"8"}}}

puts "-1- attributes: #{attributes.inspect}"

multi_parameter_attributes  = []
nested_parameter_attributes = []

attributes.each do |k, v|
  puts "-2- testing k: #{k}, v: #{v}"
  if k.include?("(")
    puts "-3- true to k.include?(\"(\")"
    multi_parameter_attributes << [ k, v ]
  elsif d.respond_to?("#{k}=")
    puts "-4- true to respond_to?(\"#{k}=\")"
    if v.is_a?(Hash)
      puts "-5- true to v.is_a?(Hash)"
      nested_parameter_attributes << [ k, v ]
    else
      puts "-6- else"
      send("#{k}=", v)
    end
  else
    puts "-7- UnknownAttributeError"
    raise(UnknownAttributeError, "unknown attribute: #{k}")
  end
end


--output:--
~/ruby_programs$ ruby -v
ruby 1.9.3p547 (2014-05-14 revision 45962) [x86_64-darwin10.8.0]
~/ruby_programs$ ruby 1.rb 
-1- attributes: {"new_book_item_attributes"=>{"1421825320.571702"=>{"content_id"=>"8"}}}
-2- testing k: new_book_item_attributes, v: {"1421825320.571702"=>{"content_id"=>"8"}}
-4- true to respond_to?("new_book_item_attributes=")
-5- true to v.is_a?(Hash)
~/ruby_programs$ rvm use 2.0.0
Using /Users/7stud/.rvm/gems/ruby-2.0.0-p481
~/ruby_programs$ ruby -v
ruby 2.0.0p481 (2014-05-08 revision 45883) [x86_64-darwin10.8.0]
~/ruby_programs$ ruby 1.rb 
-1- attributes: {"new_book_item_attributes"=>{"1421825320.571702"=>{"content_id"=>"8"}}}
-2- testing k: new_book_item_attributes, v: {"1421825320.571702"=>{"content_id"=>"8"}}
-4- true to respond_to?("new_book_item_attributes=")
-5- true to v.is_a?(Hash)
~/ruby_programs$ 

令人沮丧。 :(

【讨论】:

  • 感谢您花费时间和精力来帮助我。我用p而不是puts重复了测试,唯一的区别是每一行都被引用了,每个内部引用前面都有\,例如"-1- attributes: {\"new_book_item_attributes\"=&gt;{\"1421864036.491922\"=&gt; {\"content_id\"=&gt;\"17\"}}}"
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多