Module: SupportTableData

Extended by:
ActiveSupport::Concern
Defined in:
lib/support_table_data.rb,
lib/support_table_data/railtie.rb

Overview

This concern can be mixed into models that represent static support tables. These are small tables that have a limited number of rows, and have values that are often tied to the logic in the code.

The values that should be in support tables can be defined in YAML, JSON, or CSV files. These values can then be synced to the database and helper methods can be generated from them.

Defined Under Namespace

Classes: Railtie

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Attribute Details

.data_directoryString

The directory where data files live by default. If you are running in a Rails environment, then this will be ‘db/support_tables`. Otherwise, the current working directory will be used.

Returns:

  • (String)


352
353
354
355
356
357
358
# File 'lib/support_table_data.rb', line 352

def data_directory
  if defined?(@data_directory)
    @data_directory
  elsif defined?(Rails.root)
    Rails.root.join("db", "support_tables").to_s
  end
end

Class Method Details

.support_table_classes(*extra_classes) ⇒ Array<Class>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Return the list of all support table classes in the order they should be loaded. Note that this method relies on the classes already having been loaded by the application. It can return indeterminate results if eager loading is turned off (i.e. development or test mode in a Rails application).

If any data files exist in the default data directory, any class name that matches the file name will attempt to be loaded (i.e. “task/statuses.yml” will attempt to load the ‘Task::Status` class if it exists).

You can also pass in a list of classes that you explicitly want to include in the returned list.

Parameters:

  • extra_classes (Class)

    List of extra classes to include in the return list.

Returns:

  • (Array<Class>)

    List of classes in the order they should be loaded.



392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
# File 'lib/support_table_data.rb', line 392

def support_table_classes(*extra_classes)
  classes = []
  extra_classes.flatten.each do |klass|
    unless klass.is_a?(Class) && klass.include?(SupportTableData)
      raise ArgumentError.new("#{klass} does not include SupportTableData")
    end
    classes << klass
  end

  # Eager load any classes defined in the default data directory by guessing class names
  # from the file names.
  if SupportTableData.data_directory && File.exist?(SupportTableData.data_directory) && File.directory?(SupportTableData.data_directory)
    Dir.glob(File.join(SupportTableData.data_directory, "**", "*")).sort.each do |file_name|
      file_name = file_name.delete_prefix("#{SupportTableData.data_directory}#{File::SEPARATOR}")
      class_name = file_name.sub(/\.[^.]*/, "").singularize.camelize
      class_name.safe_constantize
    end
  end

  active_record_classes = ActiveRecord::Base.descendants.reject { |klass| klass.name.nil? }
  active_record_classes.sort_by(&:name).each do |klass|
    next unless klass.include?(SupportTableData)
    next unless klass.instance_variable_defined?(:@support_table_data_files) && klass.instance_variable_get(:@support_table_data_files).is_a?(Array)
    next if klass.abstract_class?
    next if classes.include?(klass)
    classes << klass
  end

  levels = [classes]
  checked = Set.new
  loop do
    checked << classes
    dependencies = classes.collect { |klass| support_table_dependencies(klass) }.flatten.uniq.sort_by(&:name)
    break if dependencies.empty? || checked.include?(dependencies)
    levels.unshift(dependencies)
    classes = dependencies
  end

  levels.flatten.uniq
end

.sync_all!(*extra_classes) ⇒ Hash<Class, Array<Hash>] Hash of classes synced with a list of saved changes.

Sync all support table classes. Classes must already be loaded in order to be synced.

You can pass in a list of classes that you want to ensure are synced. This feature can be used to force load classes that are only loaded at runtime. For instance, if eager loading is turned off for the test environment in a Rails application (which is the default), then there is a good chance that support table models won’t be loaded when the test suite is initializing.

Parameters:

  • extra_classes (Class)

    List of classes to force into the detected list of classes to sync.

Returns:

  • (Hash<Class, Array<Hash>] Hash of classes synced with a list of saved changes.)

    Hash<Class, Array<Hash>] Hash of classes synced with a list of saved changes.



370
371
372
373
374
375
376
# File 'lib/support_table_data.rb', line 370

def sync_all!(*extra_classes)
  changes = {}
  support_table_classes(*extra_classes).each do |klass|
    changes[klass] = klass.sync_table_data!
  end
  changes
end

Instance Method Details

#protected_instance?Boolean

Return true if this instance has data being managed from a data file. You can add validation logic using this information if you want to prevent the application from updating protected instances.

Returns:

  • (Boolean)


465
466
467
# File 'lib/support_table_data.rb', line 465

def protected_instance?
  self.class.protected_instance?(self)
end