Search code examples
ruby-on-railsruby-on-rails-4rspec-rails

Creating some class during tests (STI)


I have a class

Gate < ActiveRecord::Base
  self.inheritance_column = :kindof
# some methods
end
#  and derived
MoneyHaters < Gate
# some overloaded methods
end

with type column :kindof for STI.

Durning tests I want to create a 2-3 childs. Mainly because each derived class must be unique in the app. Like that:

factory :gate do
  before(:create) do
    gate_name  = FFaker::Company.name.gsub( /\s+/,'' )
    gate_class_name = gate_name.singularize.classify
  end

  name { gate_name }

  # I want that next class will be declared in App namespace, like all others.
  gate_class  = Class.new(Gate) do
    def comission_in(amount)
      amount * 0.01 + 5
    end
    def comission_out(amount)
      amount * 0.02 + 5
    end
  end
  Object.const_set( gate_class_name, gate_class )

  type { gate_class_name }
  country { FFaker::Address.country_code }
end

Code gave me error when ran with rspec in line "Object.const_set"

TypeError: #<FactoryGirl::Declaration::Implicit:0x00000006a1af30 @name=:gate_class_name, @ignored=false, @factory=#<FactoryGirl::Definition:0x00000006ed6df8 @declarations=#<FactoryGirl::DeclarationList:0x00000006ed6dd0 @declarations=[#<FactoryGirl::Declaration::Dynamic:0x00000006ed6998 @name=:name, @ignored=false, @block=#<Proc:0x00000006ed69c0@[skipped]>>, #<FactoryGirl::Declaration::Implicit:0x00000006a1af30 ...>], @name=:gate, @overridable=false>, @callbacks=[#<FactoryGirl::Callback:0x00000006ed6a38 @name=:before_create, @block=#<Proc:0x00000006ed6ba0@[skipped]>>], @defined_traits=#<Set: {}>, @to_create=nil, @base_traits=[], @additional_traits=[], @constructor=nil, @attributes=nil, @compiled=false>> is not a symbol nor a string

but works ok in rails console

Usually I call FactoryGirl factories for creating objects, but, if that is impossible - I wonder for any other method to do that.

Any help is very much appreciate.


Solution

  • Ok, I spend about two hours before posting the question, but I found answer only after posting =)

    I had just to move the class definition inside attribute's one.

    FactoryGirl.define do
      factory :gate do
    
        name { FFaker::Company.name }
        type { 
          class_name = 'Gate' + name.gsub( /[[:blank:][:cntrl:][:punct:]]/,'' ).to_s.singularize
          gate_class = class_name.classify
          class_instance  = Class.new(Gate) do
            def comission_in(amount)
              amount * 0.01 + 5
            end
            def comission_out(amount)
              amount * 0.02 + 5
            end
          end
          Object.const_set( gate_class, class_instance )
          puts " gate_class: '#{ gate_class }'; name: '#{ name }';"
          class_name
        }
        country { FFaker::Address.country_code }
    
      end
    end