Class: ConfigScripts::Seeds::SeedSet

Inherits:
Object
  • Object
show all
Defined in:
lib/config_scripts/seeds/seed_set.rb

Overview

This class represents a set of related seeds.

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

Registration collapse

Instance Attribute Summary collapse

Registration collapse

Batch Operations collapse

Creation collapse

Reading and Writing collapse

DSL collapse

Seed Identifiers collapse

Constructor Details

#initialize(name, set_number = 1, folder = nil, options = {}, &block) ⇒ SeedSet

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.

Parameters:

  • name (String)

    The name for the folder for the seeds.

  • set_number (Integer) (defaults to: 1)

    The set_number in which this seed set should be run.

  • folder (String) (defaults to: nil)

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

  • options (Hash) (defaults to: {})

    Additional information that can be made accessible to the seed type definitions.



150
151
152
153
154
155
156
157
158
159
# 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

Class Attribute Details

.registered_setsHash<Integer, SeedSet> (readonly)

The seed sets that have been defined.

Returns:



38
39
40
# File 'lib/config_scripts/seeds/seed_set.rb', line 38

def registered_sets
  @registered_sets
end

Instance Attribute Details

#folderString (readonly)

The name of the folder to which we will write the seeds.

Returns:

  • (String)


18
19
20
# File 'lib/config_scripts/seeds/seed_set.rb', line 18

def folder
  @folder
end

#nameString (readonly)

The name of the folder for this seed set.

Returns:

  • (String)


9
10
11
# File 'lib/config_scripts/seeds/seed_set.rb', line 9

def name
  @name
end

#optionsHash (readonly)

Arbitrary extra data passed in when defining the seed set.

Returns:

  • (Hash)


22
23
24
# File 'lib/config_scripts/seeds/seed_set.rb', line 22

def options
  @options
end

#reset_blockProc (readonly)

The block that will be run when resetting the records during a load.

Returns:

  • (Proc)


31
32
33
# File 'lib/config_scripts/seeds/seed_set.rb', line 31

def reset_block
  @reset_block
end

#seed_typesHash (readonly)

A hash mapping class names to the ConfigScripts::Seeds::SeedType instances describing how to handle seeds for that class within this set.

Returns:

  • (Hash)


27
28
29
# File 'lib/config_scripts/seeds/seed_set.rb', line 27

def seed_types
  @seed_types
end

#set_numberInteger

A number identifying this set. Seed sets will be run from the one with the lowest number to the highest.

Returns:

  • (Integer)


14
15
16
# File 'lib/config_scripts/seeds/seed_set.rb', line 14

def set_number
  @set_number
end

Class Method Details

.clear_registered_setsHash

This method wipes out our records of registered seed sets.

Returns:

  • (Hash)

    The new list of seed sets.



62
63
64
# File 'lib/config_scripts/seeds/seed_set.rb', line 62

def clear_registered_sets
  @registered_sets = {}
end

.each_set(set_number = nil, &block) ⇒ Array

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.

Parameters:

  • set_number (String) (defaults to: nil)

    The number of the set that we should run.

Returns:

  • (Array)


115
116
117
118
119
120
121
122
123
124
125
126
127
# 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

.listArray

This method lists every seed set, with its set number.

Returns:

  • (Array)


101
102
103
104
105
# 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_setsObject

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



68
69
70
71
72
# 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

.read(set_number = nil) ⇒ Array

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

Parameters:

  • set_number (Integer) (defaults to: nil)

    The number of the set to read.

Returns:

  • (Array)


93
94
95
96
97
# 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) ⇒ SeedSet

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.

Parameters:

  • set (SeedSet)

    The new seed set.

Returns:



49
50
51
52
53
54
55
56
# 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) ⇒ Array

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

Parameters:

  • set_number (Integer) (defaults to: nil)

    The number of the set to write.

Returns:

  • (Array)


83
84
85
# File 'lib/config_scripts/seeds/seed_set.rb', line 83

def write(set_number=nil)
  self.each_set(set_number, &:write)
end

Instance Method Details

#read(reset = false) ⇒ Object

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.

Parameters:

  • reset (Boolean) (defaults to: false)

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



199
200
201
# 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) ⇒ Object

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

Parameters:

  • reset (Boolean)

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

  • unscoped_classes (Array<Class>)

    The classes that we need to remove default scopes from before loading the seeds.



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# 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) ⇒ ActiveRecord::Base

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.

Parameters:

  • klass (Class)

    The model class for the record we are finding.

  • identifier (Array<String>)

    The identifier components from the seed data.

Returns:

  • (ActiveRecord::Base)

    The model record.



333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
# 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_recordsObject

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



229
230
231
# 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) ⇒ String

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.

Parameters:

  • record (ActiveRecord::Base)

    The record whose identifier we are generating.

Returns:

  • (String)


307
308
309
310
311
312
313
314
# 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) ⇒ SeedType

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

Parameters:

  • klass (Class)

    The class whose seeds we are dealing with.

Returns:



284
285
286
287
288
289
290
291
292
# 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) ⇒ SeedType

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.

Parameters:

  • klass (Class)

    The model class whose seed data this stores.

  • filename (String) (defaults to: nil)

    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.

Returns:



249
250
251
252
# 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) ⇒ Array<Class>

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

Parameters:

  • classes (Array<Class>)

    The classes to unscope.

Returns:

  • (Array<Class>)

    The new list of unscoped classes.



272
273
274
# File 'lib/config_scripts/seeds/seed_set.rb', line 272

def unscope(*classes)
  @unscoped_classes += classes
end

#when_resetting(&block) ⇒ Proc

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.

Returns:

  • (Proc)


261
262
263
# File 'lib/config_scripts/seeds/seed_set.rb', line 261

def when_resetting(&block)
  @reset_block = block
end

#writeObject

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.



167
168
169
# File 'lib/config_scripts/seeds/seed_set.rb', line 167

def write
  self.write_with_unscoped(@unscoped_classes)
end

#write_with_unscoped(unscoped_classes) ⇒ Object

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.

Parameters:

  • unscoped_classes (Array<Class>)

    The classes whose scopes we will remove.



177
178
179
180
181
182
183
184
185
186
187
188
189
190
# 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