class ConfigScripts::Seeds::SeedSet

This class represents a set of related seeds.

These seeds will be stored as CSV files in a folder together.

Attributes

registered_sets[R]

@return [Hash<Integer, SeedSet>] The seed sets that have been defined.

folder[R]

@return [String] The name of the folder to which we will write the seeds.

name[R]

@return [String] The name of the folder for this seed set.

options[R]

@return [Hash] Arbitrary extra data passed in when defining the seed set.

reset_block[R]

@return [Proc] The block that will be run when resetting the records during a load.

seed_types[R]

@return [Hash] A hash mapping class names to the {SeedType} instances describing how to handle seeds for that class within this set.

set_number[RW]

@return [Integer] A number identifying this set. Seed sets will be run from the one with the lowest number to the highest.

Public Class Methods

clear_registered_sets() click to toggle source

This method wipes out our records of registered seed sets.

@return [Hash]

The new list of seed sets.
# File lib/config_scripts/seeds/seed_set.rb, line 62
def clear_registered_sets
  @registered_sets = {}
end
each_set(set_number=nil, &block) click to toggle source

This method runs a block on each set that the app has defined.

The block will be given one parameter, which is the seed set.

@param [String] set_number

The number of the set that we should run.

@return [Array]

# File lib/config_scripts/seeds/seed_set.rb, line 115
def each_set(set_number=nil, &block)
  @registered_sets ||= {}
  self.load_seed_sets
  if set_number
    if self.registered_sets[set_number]
      block.call(self.registered_sets[set_number])
    end
  else
    self.registered_sets.keys.sort.each do |set_number|
      block.call(self.registered_sets[set_number])
    end
  end
end
list() click to toggle source

This method lists every seed set, with its set number. @return [Array]

# File lib/config_scripts/seeds/seed_set.rb, line 101
def list
  self.each_set do |set|
    puts "#{set.set_number}: #{set.name}"
  end
end
load_seed_sets() click to toggle source

This method loads all of the seed definitions from the files in the db/seeds/definitions directory.

# File lib/config_scripts/seeds/seed_set.rb, line 68
def load_seed_sets
  Dir[Rails.root.join('db', 'seeds', 'definitions', '*')].each do |file|
    require file
  end
end
new(name, set_number=1, folder=nil, options = {}, &block) click to toggle source

This method creates a new seed set.

It should be given a block, which will be run on the instance, and which should use the {#seeds_for} method to define seed types.

@param [String] name

The name for the folder for the seeds.

@param [Integer] set_number

The set_number in which this seed set should be run.

@param [String] folder

The folder that we should use for this seed set. If this is not
provided, we will use the name.

@param [Hash] options

Additional information that can be made accessible to the seed type
definitions.
# File lib/config_scripts/seeds/seed_set.rb, line 150
def initialize(name, set_number=1, folder=nil, options = {}, &block)
  @name = name.to_s
  @set_number = set_number
  @folder = folder || @name
  @options = options
  @seed_types = {}
  @unscoped_classes = []
  self.instance_eval(&block) if block_given?
  ConfigScripts::Seeds::SeedSet.register_seed_set(self)
end
read(set_number=nil) click to toggle source

This method loads the data from every seed set into the database.

@param [Integer] set_number

The number of the set to read.

@return [Array]

# File lib/config_scripts/seeds/seed_set.rb, line 93
def read(set_number=nil)
  self.each_set set_number do |set|
    set.read(set_number.present?)
  end
end
register_seed_set(set) click to toggle source

This method adds a new seed set to our registry.

If there is already a registered seed set with this set’s set_number, the number will be incremented until it is available.

@param [SeedSet] set

The new seed set.

@return [SeedSet]

# File lib/config_scripts/seeds/seed_set.rb, line 49
def register_seed_set(set)
  @registered_sets ||= {}
  while @registered_sets[set.set_number]
    return if @registered_sets[set.set_number] == set
    set.set_number += 1
  end
  @registered_sets[set.set_number] = set
end
write(set_number=nil) click to toggle source

This method writes the data for every seed set to its seed data folder.

@param [Integer] set_number

The number of the set to write.

@return [Array]

# File lib/config_scripts/seeds/seed_set.rb, line 83
def write(set_number=nil)
  self.each_set(set_number, &:write)
end

Public Instance Methods

read(reset=false) click to toggle source

This method reads the data for this seed set from its seed folder.

It will load the data for each seed type’s file, enclosing all the seed types in a transaction block.

@param [Boolean] reset

Whether we should reset the existing records before loading the seeds.
# File lib/config_scripts/seeds/seed_set.rb, line 199
def read(reset=false)
  self.read_with_unscoped(reset, @unscoped_classes)
end
read_with_unscoped(reset, unscoped_classes) click to toggle source

This method reads the data for this seed set from its seed folder.

@param [Boolean] reset

Whether we should reset the existing records before loading the seeds.

@param [Array<Class>] unscoped_classes

The classes that we need to remove default scopes from before loading
the seeds.
# File lib/config_scripts/seeds/seed_set.rb, line 211
def read_with_unscoped(reset, unscoped_classes)
  if unscoped_classes.any?
    unscoped_classes.first.unscoped { self.read_with_unscoped(reset, unscoped_classes[1..-1]) }
  else
    folder_path = Rails.root.join('db', 'seeds', 'data', self.folder)
    FileUtils.mkdir_p(folder_path)
    puts "Reading seeds for #{self.name} from #{folder_path}"
    ActiveRecord::Base.transaction do
      self.reset_records if reset
      self.seed_types.each do |klass, seed_type|
        seed_type.read_from_folder(folder_path)
      end
    end
  end
end
record_for_seed_identifier(klass, identifier) click to toggle source

This method finds a record based on a unique identifier in the seed data.

This will look for a seed type for the class, and use its {#record_for_seed_identifier} method to get the record.

The result of this will be memoized so that we do not have to keep looking up the records.

@param [Class] klass

The model class for the record we are finding.

@param [Array<String>] identifier

The identifier components from the seed data.

@return [ActiveRecord::Base]

The model record.
# File lib/config_scripts/seeds/seed_set.rb, line 333
def record_for_seed_identifier(klass, identifier)
  seed_type = self.seed_type_for_class(klass)
  return nil unless seed_type

  @record_cache ||= {}
  @record_cache[klass] ||= {}

  cache_identifier = identifier.dup

  while cache_identifier.any?
    record = @record_cache[klass][cache_identifier]
    if record
      cache_identifier.count.times { identifier.shift }
      return record
    end
    cache_identifier.pop
  end

  if seed_type
    cache_identifier = identifier.dup
    record = seed_type.record_for_seed_identifier(identifier)

    if identifier.any?
      cache_identifier = cache_identifier[0...-1*identifier.count]
    end

    @record_cache[klass][cache_identifier] = record
  end
  record
end
reset_records() click to toggle source

This method resets all the existing records that could be populated by this seed set.

# File lib/config_scripts/seeds/seed_set.rb, line 229
def reset_records
  self.reset_block.call if self.reset_block
end
seed_identifier_for_record(record) click to toggle source

This method gets a unique identifier for a record when writing seeds that refer to it.

It will look for a seed type that handles seeds for a class in the record’s class heirarchy, and use that seed type’s {#seed_identifier_for_record} method. If it cannot find a seed type, it will use the record’s ID.

@param [ActiveRecord::Base] record

The record whose identifier we are generating.

@return [String]

# File lib/config_scripts/seeds/seed_set.rb, line 307
def seed_identifier_for_record(record)
  seed_type = self.seed_type_for_class(record.class)
  if seed_type
    seed_type.seed_identifier_for_record(record)
  else
    record.id rescue nil
  end
end
seed_type_for_class(klass) click to toggle source

This method gets a seed type that we have on file for a class.

@param [Class] klass

The class whose seeds we are dealing with.

@return [SeedType]

# File lib/config_scripts/seeds/seed_set.rb, line 284
def seed_type_for_class(klass)
  while klass && klass != ActiveRecord::Base
    seed_type = self.seed_types[klass]
    if seed_type
      return seed_type
    end
    klass = klass.superclass
  end
end
seeds_for(klass, filename=nil, &block) click to toggle source

This method defines a new seed type within this seed set.

This method should be given a block, which will be passed to the initializer for the new seed type.

@param [Class] klass

The model class whose seed data this stores.

@param [String] filename

The name of the file in which the seed data should be stored.
If this is not provided, it will use the name of the class.
This should not include the file extension.

@return [SeedType]

# File lib/config_scripts/seeds/seed_set.rb, line 249
def seeds_for(klass, filename=nil, &block)
  filename ||= klass.name.underscore.pluralize
  @seed_types[klass] = SeedType.new(self, klass, filename, &block)
end
unscope(*classes) click to toggle source

This method specifies classes that will be unscoped when writing the seed data.

@param [Array<Class>] classes

The classes to unscope.

@return [Array<Class>]

The new list of unscoped classes.
# File lib/config_scripts/seeds/seed_set.rb, line 272
def unscope(*classes)
  @unscoped_classes += classes
end
when_resetting(&block) click to toggle source

This method defines a block that will be run when resetting existing records.

This block will be run when loading a seed set as a one-off, but not when loading all the seed sets.

@return [Proc]

# File lib/config_scripts/seeds/seed_set.rb, line 261
def when_resetting(&block)
  @reset_block = block
end
write() click to toggle source

This method writes the data for this seed set to its seed folder.

It will create the folder and then write the file for each seed type that has been defined.

# File lib/config_scripts/seeds/seed_set.rb, line 167
def write
  self.write_with_unscoped(@unscoped_classes)
end
write_with_unscoped(unscoped_classes) click to toggle source

This method writes the data for this seed set to its seed folder.

It will remove all default scopes from the classes provided before doing the write.

@param [Array<Class>] unscoped_classes

The classes whose scopes we will remove.
# File lib/config_scripts/seeds/seed_set.rb, line 177
def write_with_unscoped(unscoped_classes)
  if unscoped_classes.any?
    unscoped_classes.first.unscoped do
      self.write_with_unscoped(unscoped_classes[1..-1])
    end
  else
    folder_path = Rails.root.join('db', 'seeds', 'data', self.folder)
    FileUtils.mkdir_p(folder_path)
    puts "Writing seeds for #{self.name} to #{folder_path}"
    self.seed_types.each do |klass, seed_type|
      seed_type.write_to_folder(folder_path)
    end
  end
end