ActiveRecord::UnknownAttributeError после обновления с Rails 3.2.7 до 3.2.21 и Ruby 1.9.3 до 2.0.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

Я просмотрела каждую запись блога на http://weblog.rubyonrails.org/releases/ из Выпущена версия Rails 3.2.8.rc1! to Выпущены версии 3.2.21, 4.0.12 и 4.1.8, и я не заметил ничего радикального, что могло бы объяснить это проблема. В любом случае, это было обновление «на уровне патча», поэтому я не ожидал каких-либо радикальных изменений. Есть идеи, что может быть виновато?


Обновить

  • Эта проблема не возникает с 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. Любые идеи о том, как я должен отлаживать дальше?


person user664833    schedule 21.01.2015    source источник
comment
Как насчет публикации всего действия, где возникает ошибка?   -  person 7stud    schedule 21.01.2015
comment
Что произойдет, если вы добавите пустой геттер для new_book_item_attributes?   -  person 7stud    schedule 21.01.2015
comment
Спасибо за ваши комментарии. Я обновил свой вопрос с некоторой отладкой, которую я сделал. В настоящее время кажется, что проблема была в Ruby, хотя я не уверен, как продолжить отладку.   -  person user664833    schedule 21.01.2015
comment
Между двумя вашими атрибутами контроллера есть два различия: 1) вложенные значения --> не должны иметь значения, потому что проблема заключается в ключе. 2) Змеиное имя против одного имени; или... длинное имя против короткого имени. Можете ли вы попробовать изменить имя вашего виртуального атрибута на x?   -  person 7stud    schedule 21.01.2015
comment
Я изменил виртуальный атрибут на xxx, и проблема была идентична. Еще раз большое спасибо за вашу помощь.   -  person user664833    schedule 21.01.2015


Ответы (2)


Я подозреваю, что здесь отсутствует какой-то контекст, который вызывает проблему, поскольку это неочевидно из того, что вы предоставили.

Вот несколько вариантов, как это отследить.

  • Узнайте, какой код в rails вызывает это исключение. Ruby делает это очень просто. Вы можете либо удалить свои глушители обратной трассировки (вероятно, в config/initializers/backtrace_silencers.rb), либо вы можете найти исходный код Rails для UnknownAttributeError. Как оказалось, есть только одно место, где возникает эта ошибка:

    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 и посмотрите, видите ли вы ошибку или нет. Как только вы изолируете версию, которая сломала ее, вы можете просмотреть diff и/или журнал изменений, чтобы увидеть, что изменилось. По крайней мере, сужение круга вопросов поможет другим помочь вам.

  • Можете ли вы сделать минимальную копию? Сколько кода вы можете удалить из своей модели, но проблема все еще будет проявляться? Можете ли вы воспроизвести проблему с помощью автономного сценария ActiveRecord? то есть что-то вроде активная запись в автономном Ruby

Надеюсь, это поможет, дайте мне знать, как вы идете!

person Xavier Shay    schedule 21.01.2015
comment
Большое спасибо за ваш развернутый ответ - для меня большая честь, что вы ответили между прочим, поскольку я знаком с некоторыми вашими работами с базами данных.. :) В любом случае, я разделил свой путь к определению того, что на самом деле версия Ruby был виновником. (Недавно я также обновил Ruby - я просто не подумал упомянуть об этом, когда впервые опубликовал свой вопрос.) Поэтому я понизил версию Ruby 2.0.0 до 1.9.3, и проблема исчезла. Смотрите мой обновленный вопрос - я не уверен, как продолжить дальнейшую отладку. Мысли? - person user664833; 21.01.2015

Я не вижу здесь никакой разницы между 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 вместо put для вывода строк?

И я получаю один и тот же результат в обеих версиях 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$ 

Раздражающий. :(

person 7stud    schedule 21.01.2015
comment
Спасибо за ваше время и усилия в попытке помочь мне. Я повторил тест с p, а не puts, и единственная разница в том, что каждая строка заключена в кавычки, а каждой внутренней кавычке предшествует \, например. "-1- attributes: {\"new_book_item_attributes\"=>{\"1421864036.491922\"=> {\"content_id\"=>\"17\"}}}" - person user664833; 21.01.2015