Module: AIFaker::ModelIntrospector

Defined in:
lib/AIFaker/model_introspector.rb

Class Method Summary collapse

Class Method Details

.app_modelsObject



46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/AIFaker/model_introspector.rb', line 46

def app_models
  base =
    if defined?(ApplicationRecord)
      ApplicationRecord
    else
      ActiveRecord::Base
    end

  base.descendants
    .reject(&:abstract_class?)
    .reject { |m| m.name.nil? || m.name.empty? }
    .sort_by(&:name)
end

.describe_associations(model) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
# File 'lib/AIFaker/model_introspector.rb', line 76

def describe_associations(model)
  model.reflections.values.map do |r|
    {
      name: r.name.to_s,
      macro: r.macro.to_s,
      class_name: r.class_name.to_s,
      foreign_key: r.foreign_key.to_s,
      optional: (r.respond_to?(:options) ? !!r.options[:optional] : false)
    }
  end
end

.describe_model(model) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/AIFaker/model_introspector.rb', line 60

def describe_model(model)
  {
    name: model.name,
    table_name: model.table_name,
    primary_key: model.primary_key,
    columns: model.columns.map do |c|
      {
        name: c.name,
        type: c.type.to_s,
        null: c.null,
        default: c.default
      }
    end
  }
end

.describe_models_and_associationsObject



7
8
9
10
11
12
13
14
15
16
17
18
# File 'lib/AIFaker/model_introspector.rb', line 7

def describe_models_and_associations
  ensure_active_record!

  eager_load_models!
  models = app_models
  associations = models.to_h { |m| [m.name, describe_associations(m)] }

  {
    models: models.map { |m| describe_model(m) },
    associations:
  }
end

.eager_load_models!Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/AIFaker/model_introspector.rb', line 26

def eager_load_models!
  return unless defined?(Rails) && Rails.respond_to?(:application) && Rails.application

  # In development, Rails often doesn't eager-load models, so descendants can be empty.
  # We force-load model files so association introspection works during `db:seed`.
  Rails.application.eager_load!

  models_dir = Rails.root.join("app/models")
  loader =
    if defined?(ActiveSupport::Dependencies) && ActiveSupport::Dependencies.respond_to?(:require_dependency)
      ActiveSupport::Dependencies.method(:require_dependency)
    else
      method(:require)
    end

  Dir.glob(models_dir.join("**/*.rb")).sort.each { |f| loader.call(f) }
rescue LoadError, StandardError
  # best-effort; not fatal (but if this fails, seeding may not see all models)
end

.ensure_active_record!Object

Raises:



20
21
22
23
24
# File 'lib/AIFaker/model_introspector.rb', line 20

def ensure_active_record!
  return if defined?(ActiveRecord::Base)

  raise MissingRailsError, "ActiveRecord is not loaded. Run AIFaker from a Rails app."
end