Nepal on Rails

millisami's rants!

Factory Girl Traits and List for Has_many Through Relation

Right now, I’m adding a feature to the rails app which brought up the has_many through association to be used. So to test this out, I need the factory for this relationship.

Following is the releationship between the models.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class GpsPosition < ActiveRecord::Base
  has_many :gps_trackings
  has_many :modem_registries, through: :gps_trackings
end

class ModemRegistry < ActiveRecord::Base
  has_many :gps_trackings
  has_many :gps_positions, through: :gps_trackings
end

class GpsTracking < ActiveRecord::Base
  belongs_to :modem_registry
  belongs_to :gps_position
end

Using Traits

The requirement for the setup is that when I create an instance of ModemRegistry, it should have at least one GpsPosition to be created.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
FactoryGirl.define do
  factory :gps_position do
    gps_location 'POINT(-83.64753 40.80664)'
  end

  factory :modem_registry do
    wireless_system 'CDMA'

    trait :with_gps_position do
      after(:create) do |modem_registry|
        modem_registry.gps_positions << create(:gps_position)
      end
    end
  end
end

Now we can create modem_registry with create(:modem_registry, :with_gps_position)

If you need the option to pass your own gps_position too, we can use the evaluator to handle this.

1
2
3
4
5
6
7
8
9
10
11
12
13
  factory :modem_registry, class: ModemRegistry do
    ...
    trait :with_gps_positions do
      ignore do
        gps_position { create(:gps_position) }
      end

      after(:create) do |modem_registry, evaluator|
        modem_registry.gps_positions << evaluator.gps_position
        modem_registry.save
      end
    end
  end

Now you can pass custom gps_position as:

1
2
another_gps_position = create(:gps_position)
create(:modem_registry_with_gps_position, gps_position: another_gps_position)

Using Create List

If you need to create a collection/list of gps_positions for a modem_registry, then we can use the create_list method.

1
2
3
4
5
6
7
8
9
trait :with_gps_positions do
  ignore do
    number_of_gps_positions 1
  end

  after(:create) do |modem_registry, evaluator|
    create_list(:gps_tracking, evaluator.number_of_gps_positions, modem_registry: modem_registry)
  end
end

And it can be used as:

1
2
3
4
5
create(:modem_registry, :with_gps_positions)
#=> will create 1 modem_registry with 1 gps_position

create(:modem_registry, :with_gps_positions, number_of_gps_positions: 10)
#=> #=> will create 1 modem_registry with 10 gps_positions

Happy testing!

Comments