"неопределенный метод` scan 'для nil: NilClass "для полиморфной ассоциации ActiveRecord с: inverse_of - PullRequest
1 голос
/ 29 марта 2019

У меня проблема с отношением has_many, когда я получаю случайное исключение из ActiveRecord:

product = Product.create!(valid_attributes)
product.prices 
# throws:
NoMethodError:
       undefined method `scan' for nil:NilClass

Похоже, это связано с "inverse_of", но я, по-видимому, сделал то, чего ActiveRecord не ожидал, но не мог быть обеспокоен, чтобы получить хорошую ошибку. Лучше всего предположить, что это как-то связано с моим столбцом с именем «столбец» (хотя его нет в черном списке AFAIK). Я использую PostgreSQL. РЕДАКТИРОВАТЬ: попытался переименовать столбец в «column_name» и «parent_column», но это не помогло. Попробую еще кое-что.

Вот соответствующий код модели и схема:

class Price < ApplicationRecord
  belongs_to :parent, polymorphic: true
end

class Product < ApplicationRecord
  has_many :prices, as: :parent, inverse_of: :parent
end

class CreatePrices < ActiveRecord::Migration[5.2]
  def change
    create_table :prices do |t|
      t.string :parent_type, null: false
      t.bigint :parent_id, null: false
      t.string :column, null: false
      t.decimal :price, null: false, precision: 15, scale: 2
      t.timestamp :effective_date, null: false
    end

    add_index :prices, [:parent_type, :parent_id, :column]
  end
end

И полная трассировка стека:

NoMethodError:
       undefined method `scan' for nil:NilClass
     # /Users/william/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/activerecord-5.2.2.1/lib/active_record/inheritance.rb:185:in `compute_type'
     # /Users/william/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/activerecord-5.2.2.1/lib/active_record/reflection.rb:422:in `compute_class'
     # /Users/william/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/activerecord-5.2.2.1/lib/active_record/reflection.rb:379:in `klass'
     # /Users/william/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/activerecord-5.2.2.1/lib/active_record/reflection.rb:234:in `inverse_of'
     # /Users/william/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/activerecord-5.2.2.1/lib/active_record/reflection.rb:239:in `check_validity_of_inverse!'
     # /Users/william/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/activerecord-5.2.2.1/lib/active_record/reflection.rb:474:in `check_validity!'
     # /Users/william/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/activerecord-5.2.2.1/lib/active_record/associations/association.rb:26:in `initialize'
     # /Users/william/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/activerecord-5.2.2.1/lib/active_record/associations.rb:237:in `new'
     # /Users/william/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/activerecord-5.2.2.1/lib/active_record/associations.rb:237:in `association'
     # /Users/william/.rbenv/versions/2.5.5/lib/ruby/gems/2.5.0/gems/activerecord-5.2.2.1/lib/active_record/associations/builder/association.rb:108:in `prices'

1 Ответ

0 голосов
/ 01 апреля 2019

Ответ состоял в том, что я нарушал ожидания ActiveRecord способом, которого я не осознавал и должен был включить в исходный вопрос, но не из-за высокомерия. Я использовал анонимную модель в тестировании. Например:

module Priced
  extend ActiveSupport::Concern

  included do
    has_many :prices, as: :parent, inverse_of: :parent
  end
end

RSpec.describe Priced do
  let(:model_class) {
    Class.new(ActiveRecord::Base).tap do |klass|
      klass.table_name = "products"
      klass.send(:include, Priced)
    end
  end

  it "defines a 'has_many :prices' association" do
    model = model_class.create!
    price = Price.create!(parent: model, price: 100)
    expect(model.prices).to eq([price])
  end
end

Это позволяет мне использовать модель ActiveRecord с существующей таблицей, но отсоединить ее от всей логики в реальной модели Product.

Я никогда раньше не сталкивался с какими-либо проблемами с этой настройкой, поэтому я успешно использовал ее для тестирования модулей в течение многих лет. Итак, моя вина если бы я поместил этот код в исходный вопрос, я, вероятно, понял бы ответ перед публикацией, но я отвечаю на свой вопрос в качестве предупреждения для других «умных» кодировщиков Ruby.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...