从Rails 3.2.7升级到3.2.21和Ruby 1.9.3升级到2.0.0后,ActiveRecord :: UnknownAttributeError

时间:2015-01-21 01:23:38

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

我刚刚将旧版应用从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

我查看了来自 Rails的http://weblog.rubyonrails.org/releases/中的每个博客条目3.2.8.rc1已经发布! Rails 3.2.21,4.0.12和4.1.8已被释放,我没有发现可能解释这个问题的任何激烈的事情。无论如何,这是一个&#34;补丁级别&#34;升级,所以我不希望任何重大变化。知道什么可能有问题吗?


更新

  • Rails 3.2.21和Ruby 1.9.3不会发生此问题(只有Ruby 2.0.0才会出现此问题(无论Rails(3.2.21还是3.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。关于我应该如何进一步调试的任何想法?

2 个答案:

答案 0 :(得分:2)

我怀疑这里缺少一些造成问题的背景,因为从你所提供的内容来看,它是不明显的。

以下是一些如何跟踪此选项的选项。

  • 找出 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

  • 之类的东西

希望有所帮助,让我知道你的去向!

答案 1 :(得分: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$ 

令人沮丧。 :(