Skip to content

Instantly share code, notes, and snippets.

@wycleffsean
Created August 23, 2019 16:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wycleffsean/b7ac7ebfa2754c3e2760c6a57393e308 to your computer and use it in GitHub Desktop.
Save wycleffsean/b7ac7ebfa2754c3e2760c6a57393e308 to your computer and use it in GitHub Desktop.
Generate Entity Relationship Model for ActiveRecord with GraphViz
namespace :graph do
desc 'build graph of AR models'
task models: :environment do
require 'graphviz'
Rails.application.eager_load!
g = GraphViz.new('Models', path: Rails.root.join('tmp').to_s)
nodes = ObjectSpace.each_object(Class)
.select { |c| c < ActiveRecord::Base }
.map { |c| GraphNode.new(g, c) }
nodes
.each { |m| m.nodes = nodes }
.each(&:call)
g.output(png: "models.png")
end
end
class GraphNode < Struct.new(:g, :model)
attr_accessor :nodes
attr_reader :node
def initialize(*args)
super
@node = g.add_nodes(model.name)
end
def call
add_parents
add_children
end
def add_parents
reflections(kind: :belongs_to).each do |parent|
g.add_edges(@node, parent.node, style: "solid" )
end
end
def add_children
reflections(kind: :has_many).each do |child|
g.add_edges(@node, child.node, style: "dotted" )
end
reflections(kind: :has_one).each do |child|
g.add_edges(@node, child.node, style: "dotted" )
end
end
def reflections(kind:)
model.reflections
.select { |_, assoc| assoc.macro == kind }
.map { |label, assoc|
begin
nodes.find{|n| n.model == assoc.klass}
rescue NameError => e
puts '-'*80
puts "for #{model.name}"
puts e
puts '-'*80
nil
end
}.compact
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment