Jake Prime
Jake Prime

Reputation: 13

Is it bad to create ActiveRecord objects in a constant?

I have some code where I create ActiveRecord objects as constants in my model like so:

class OrderStage < ActiveRecord::Base
  validates :name, presence: true, uniqueness: true

  DISPATCHED = find_or_create_by(name: 'Dispatched')
end

Each Order has an OrderStage:

class Order < ActiveRecord::Base
  belongs_to :order_stage
end

Now this seems to work fine throughout the site, and in my integration tests. However it is breaking in my unit test. The following test

it 'lists all order stages' do
  # using FactoryGirl
  create(:order, order_stage: OrderStage::DISPATCHED)
  expect(Order.all.map(&:order_stage)).to eq [OrderStage::DISPATCHED]
end

passes fine when I run it individually, or when I run just order_spec.rb. But when I run the whole test suite, or even just spec/models I get this error:

Failure/Error: expect(Order.all.map(&:order_stage)).to eq [OrderStage::DISPATCHED]

   expected: [#<OrderStage id: 1, name: "Dispatched">]
        got: [nil]

That error goes away if I write my test like so:

it 'lists all order stages' do
  order_stage = OrderStage.find_or_create_by(name: 'Dispatched')
  create(:order, order_stage: order_stage)
  expect(Order.all.map(&:order_stage)).to eq [order_stage]
end

So it must be something to do with creating the ActiveRecord object in the constant, it this a bad thing to do?

Upvotes: 1

Views: 91

Answers (1)

Santanu
Santanu

Reputation: 960

You should use class method.

attr_accessible :name

def self.dispatched
  @dispatched ||= find_or_create_by_name('Dispatched')
end

private

def self.reset!
  @dispatched = nil
end

Upvotes: 1

Related Questions