Остановка константы модели для ассоциации (неопределенный метод `lation_delegate_class')

У меня есть Lesson модель, которая связана с Permission модель:

app/models/lesson.rb:

class Lesson < ActiveRecord::Base
  has_many :permissions, :class_name => 'Permission', as: :permissible, dependent: :destroy
  ...

  def create_permissions
    Permission::DEFAULTS[:lesson].each do |action, value|
      ..
    end
  end

app/models/permission.rb:

class Permission < ActiveRecord::Base
  DEFAULTS = {
    lesson: {some_more_action: 15}
  }

  belongs_to :permissible, polymorphic: true
end

Я использовал RSpec stub_const метод заглушки вложенной определенной константы:

spec/models/lesson_spec.rb:

require 'rails_helper'

RSpec.describe Lesson, :type => :model do
  describe "#create_permissions" do
    let!(:lesson) { FactoryGirl.build_stubbed :lesson }

    before(:each) do
      stub_const('Permission::DEFAULTS', {lesson: {some_action: 5}})
    end

    it 'should create permissions' do
      lesson.create_permissions

      permission = lesson.permissions.first

      ...
    end
  end
end

Но спецификации не удается с ошибкой:

Failure/Error: permission = lesson.permissions.first
NoMethodError:
  undefined method `relation_delegate_class' for Permission:Module
 # /home/install/.rvm/gems/ruby-2.1.4/gems/activerecord-4.2.3/lib/active_record/relation/delegation.rb:112:in `relation_class_for'
 # /home/install/.rvm/gems/ruby-2.1.4/gems/activerecord-4.2.3/lib/active_record/relation/delegation.rb:106:in `create'
 # /home/install/.rvm/gems/ruby-2.1.4/gems/activerecord-4.2.3/lib/active_record/associations/collection_association.rb:41:in `reader'
 # /home/install/.rvm/gems/ruby-2.1.4/gems/activerecord-4.2.3/lib/active_record/associations/builder/association.rb:115:in `permissions'
 # ./spec/models/lesson_spec.rb:285:in `block (3 levels) in <top (required)>'

Это выглядит, как если бы permissions больше не рельсы, связанные с моделью урока. Любые идеи о том, как пройти этот раунд.

Gem версии: rspec-3.3.0, rspec-rails-3.3.3, rails-4.2.3,

2 ответа

Решение

Внимательно посмотрите на это сообщение об ошибке:

NoMethodError:
  undefined method `relation_delegate_class' for Permission:Module

Permission описывается как Module здесь, а не как Class, Я думаю, что это происходит потому, что в момент заглушения вложенного const, Permission класс еще не загружен, и RSpec тоже должен заглушить его через Module,

Попробуйте это в качестве обходного пути:

before(:each) do
  Permission # load real ActiveRecord Permission class
  stub_const('Permission::DEFAULTS', {lesson: {some_action: 5}})
end

РЕДАКТИРОВАТЬ: Как примечание, я не думаю, что представление вложенных констант другим классам является хорошей идеей, у вас мало контроля над константой (просто изменение имени или значения), и вы не можете обернуть любое поведение, как вы делаете это методом. Я рекомендую сменить публику PermissionAPI для использования метода, также будет проще заглушки:

class Permission < ActiveRecord::Base
  DEFAULTS = {
    lesson: {some_more_action: 15}
  }

  def self.defaults
    DEFAULTS
  end    
end

И в вашей спецификации:

before(:each) do
  allow(Permission).to receive(:defaults).and_return(lesson: {some_action: 5})
end

Единственный вариант, на который я натолкнулся, это просто явно указать константу в примере:

before(:each) do
  Permission::DEFAULTS = {lesson: {some_action: 5}}
end

Но я не чувствую, что это хорошая идея. Это поднимает пару предупреждений также:

spec/models/lesson_spec.rb:279: warning: already initialized constant Permission::DEFAULTS
app/models/permission.rb:2: warning: previous definition of DEFAULTS was here
Другие вопросы по тегам