Rails 3 ActiveRecord:: Отношение случайных ассоциаций поведения

В настоящее время у меня странная проблема с приложением, перенесенным с рельсов 2.3.8 на рельсы 3 (3.0.1, 3.0.2, 3.0.3). В случайные моменты ассоциации ведут себя странно. В некоторых случаях связанный объект будет возвращать объект Relation вместо соответствующей модели. Похоже, это происходит в основном при полиморфных ассоциациях. Например:

class A
  belongs_to :b, :polymorphic => true
end

class B
  has_many :a, :as => :source
end

При вызове "ab" это "иногда" возвращает объект Relation (что приводит к возникновению ошибки "неопределенный метод... для ActiveRecord::Relation"), а в некоторых других случаях он возвращает правильный объект B. Когда объект отношения возвращается, его иногда можно временно исправить, перезапустив сервер, но в конечном итоге он снова появится.

Другая проблема, которую я получаю, заключается в том, что при "получении" связанных объектов иногда необходимые фильтры не применяются автоматически (где элемент id =...). это заставляет запрос возвращать первый объект в таблице, а не правильный связанный объект.

Это становится очень неприятной проблемой, особенно потому, что я, кажется, не нахожу никого другого с этой или схожими проблемами.

Все методы поиска в приложении были перенесены в новую форму rails, но это странное поведение сохраняется.

Используемая текущая конфигурация: Ubuntu 10 nginx server passenger (3.0.2) rails (3.0.3) ruby ​​1.9.2p0 (2010-08-18 revision 29036)

2 ответа

Решение

После более глубокого изучения кода Active Record мой коллега и я обнаружили, что own_to_association.rb и assign_to_polymorphic_association.rb все еще использовали старые методы поиска в методе "find_target".

Мы запустили пару тестов, зарегистрировав получившиеся объекты этого метода из разных запросов и обнаружили, что старые искатели возвращали ActiveRecord::Relation в случайные моменты (при загрузке одного и того же объекта он иногда возвращал объект, а иногда объект Relation).

Мы переопределили метод find_target для этих двух классов в файлах инициализатора, изменив используемые там искатели на новый формат rails3 (klass.select(...). Where (...) и т. Д.). Это, кажется, решило проблему.

Файлы ассоциации has_many уже используют новый формат, поэтому они не вызвали никаких проблем.

Мы применили эти "исправления" к рельсам 3.0.3 и надеемся, что они будут исправлены в будущих выпусках.

Вот наши файлы инициализатора на случай, если кто-то еще столкнется с этой проблемой: own_to_polymorphic_association.rb:

#initializers/belongs_to_polymorphic_association.rb
module ActiveRecord
  # = Active Record Belongs To Polymorphic Association
  module Associations
    class BelongsToPolymorphicAssociation < AssociationProxy #:nodoc:
      private
        def find_target
          return nil if association_class.nil?

          target =
            if @reflection.options[:conditions]
              association_class.select(@reflection.options[:select]).where(conditions).where(:id => @owner[@reflection.primary_key_name]).includes(@reflection.options[:include]).first
            else
              association_class.select(@reflection.options[:select]).where(:id => @owner[@reflection.primary_key_name]).includes(@reflection.options[:include]).first
            end
          set_inverse_instance(target, @owner)

          target
        end      
    end
  end
end

belongs_to_association.rb:

#initializers/belongs_to_association.rb
module ActiveRecord
  # = Active Record Belongs To Associations
  module Associations
    class BelongsToAssociation < AssociationProxy #:nodoc:

      private
        def find_target
          key_column = (@reflection.options[:primary_key]) ? @reflection.options[:primary_key].to_sym : :id

          options = @reflection.options.dup
          (options.keys - [:select, :include, :readonly]).each do |key|
            options.delete key
          end
          options[:conditions] = conditions

          the_target= @reflection.klass.select(options[:select]).where(key_column => @owner[@reflection.primary_key_name]).where(options[:conditions]).includes(options[:include]).readonly(options[:readonly]).order(options[:order]).first if @owner[@reflection.primary_key_name]
          set_inverse_instance(the_target, @owner)
          the_target
        end

    end
  end
end

Надеюсь, что это полезно для кого-то

Спасибо, что поделились этим. Проблема с ассоциациями ушла. Но у меня все еще была эта проблема даже с прямым методом "найти".

@post = Post.find(params[:id)
@post.update_attributes...

потерпит неудачу с ошибкой ActiveRecord::Relation. тем не мение

@post = Post.find_by_id(params[:id])
@post.update_attributes...

буду работать

Похоже на странное ленивое поведение при загрузке

Другие вопросы по тегам