rails-erd 1.5.2 → 1.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/README.md +12 -6
- data/lib/rails_erd/cli.rb +25 -7
- data/lib/rails_erd/config.rb +13 -3
- data/lib/rails_erd/diagram/graphviz.rb +15 -3
- data/lib/rails_erd/diagram.rb +2 -2
- data/lib/rails_erd/domain/attribute.rb +3 -3
- data/lib/rails_erd/domain/entity.rb +1 -1
- data/lib/rails_erd/domain/relationship.rb +1 -2
- data/lib/rails_erd/domain/specialization.rb +8 -1
- data/lib/rails_erd/domain.rb +45 -4
- data/lib/rails_erd/tasks.rake +16 -4
- data/lib/rails_erd/version.rb +1 -1
- data/lib/rails_erd.rb +1 -0
- data/test/test_helper.rb +40 -14
- data/test/unit/attribute_test.rb +10 -11
- data/test/unit/config_test.rb +29 -0
- data/test/unit/diagram_test.rb +9 -0
- data/test/unit/domain_test.rb +24 -6
- data/test/unit/graphviz_test.rb +24 -6
- data/test/unit/rake_task_test.rb +18 -0
- metadata +39 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8b58372ac1652af1b21bd00ea88b434bb2d303247eca241f57efd84210bc9367
|
4
|
+
data.tar.gz: aecdcd4cfdb25ed3ef1713da019b456512d2b7bc965ebe0d7acea86e56b4f586
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1d8c7c596bf41d7753c0c34a468c142021ed66e7b7168dab70f68e57cf587640b5d5c35693b14c4a4c7778cf55b30f5740393454773901720f29c71f16e91c73
|
7
|
+
data.tar.gz: 733fe6e3c637a1f31f750621af09b9803102663b8d5cb611f978c600bc0940856e491a853325f57b4c126cf6e1ec50d55a4d0425ed573f1b722f144333ff4cf9
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Rails ERD - Generate Entity-Relationship Diagrams for Rails applications
|
2
2
|
========================================================================
|
3
|
-
[](https://github.com/voormedia/rails-erd/actions/workflows/test.yml) [](https://codeclimate.com/github/voormedia/rails-erd)
|
4
4
|
|
5
5
|
[Rails ERD](https://voormedia.github.io/rails-erd/) is a gem that allows you to easily generate a diagram based on your application's Active Record models. The diagram gives an overview of how your models are related. Having a diagram that describes your models is perfect documentation for your application.
|
6
6
|
|
@@ -30,9 +30,11 @@ Getting started
|
|
30
30
|
|
31
31
|
See the [installation instructions](https://voormedia.github.io/rails-erd/install.html) for a complete description of how to install Rails ERD. Here's a summary:
|
32
32
|
|
33
|
-
* Install Graphviz 2.22+ ([how?](https://voormedia.github.io/rails-erd/install.html))
|
33
|
+
* Install Graphviz 2.22+ ([how?](https://voormedia.github.io/rails-erd/install.html)). On macOS with Homebrew run `brew install graphviz`.
|
34
34
|
|
35
|
-
*
|
35
|
+
* on linux - `sudo apt-get install graphviz`
|
36
|
+
|
37
|
+
* Add <tt>gem 'rails-erd', group: :development</tt> to your application's Gemfile
|
36
38
|
|
37
39
|
* Run <tt>bundle exec erd</tt>
|
38
40
|
|
@@ -44,7 +46,7 @@ Rails ERD has the ability to be configured via the command line or through the u
|
|
44
46
|
```yaml
|
45
47
|
attributes:
|
46
48
|
- content
|
47
|
-
-
|
49
|
+
- foreign_keys
|
48
50
|
- inheritance
|
49
51
|
disconnected: true
|
50
52
|
filename: erd
|
@@ -64,13 +66,17 @@ only_recursion_depth: null
|
|
64
66
|
prepend_primary: false
|
65
67
|
cluster: false
|
66
68
|
splines: spline
|
69
|
+
fonts:
|
70
|
+
normal: "Arial"
|
71
|
+
bold: "Arial Bold"
|
72
|
+
italic: "Arial Italic"
|
67
73
|
```
|
68
74
|
|
69
75
|
Auto generation
|
70
76
|
---------------
|
71
77
|
|
72
|
-
* Run <tt>rails
|
73
|
-
* Run <tt>rails db:migrate</tt>, then the diagram is generated
|
78
|
+
* Run <tt>bundle exec rails g erd:install</tt>
|
79
|
+
* Run <tt>bundle exec rails db:migrate</tt>, then the diagram is generated
|
74
80
|
|
75
81
|
Learn more
|
76
82
|
----------
|
data/lib/rails_erd/cli.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require "rails_erd"
|
1
2
|
require "choice"
|
2
3
|
|
3
4
|
Choice.options do
|
@@ -125,6 +126,12 @@ Choice.options do
|
|
125
126
|
exit
|
126
127
|
end
|
127
128
|
end
|
129
|
+
|
130
|
+
option :config_file do
|
131
|
+
short "-c"
|
132
|
+
long "--config=FILENAME"
|
133
|
+
desc "Configuration file to use"
|
134
|
+
end
|
128
135
|
end
|
129
136
|
|
130
137
|
module RailsERD
|
@@ -143,6 +150,9 @@ module RailsERD
|
|
143
150
|
opts[key.to_sym] = value
|
144
151
|
end
|
145
152
|
end
|
153
|
+
if options[:config_file] && options[:config_file] != ''
|
154
|
+
RailsERD.options = RailsERD.default_options.merge(Config.load(options[:config_file]))
|
155
|
+
end
|
146
156
|
new(path, options).start
|
147
157
|
end
|
148
158
|
end
|
@@ -164,17 +174,25 @@ module RailsERD
|
|
164
174
|
|
165
175
|
def load_application
|
166
176
|
$stderr.puts "Loading application in '#{File.basename(path)}'..."
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
rescue ::LoadError
|
171
|
-
puts "Please create a file in '#{environment_path}' that loads your application environment."
|
172
|
-
raise
|
173
|
-
end
|
177
|
+
environment_path = "#{path}/config/environment.rb"
|
178
|
+
require environment_path
|
179
|
+
|
174
180
|
if defined? Rails
|
175
181
|
Rails.application.eager_load!
|
176
182
|
Rails.application.config.eager_load_namespaces.each(&:eager_load!) if Rails.application.config.respond_to?(:eager_load_namespaces)
|
177
183
|
end
|
184
|
+
rescue ::LoadError
|
185
|
+
error_message = <<~EOS
|
186
|
+
Tried to load your application environment from '#{environment_path}' but the file was not present.
|
187
|
+
This means that your models might not get loaded fully when the diagram gets built. This can
|
188
|
+
make your entity diagram incomplete.
|
189
|
+
|
190
|
+
However, if you are using ActiveRecord without Rails just make sure your models get
|
191
|
+
loaded eagerly before we generate the ERD (for example, explicitly require your application
|
192
|
+
bootstrap file before calling rails-erd from your Rakefile). We will continue without loading the environment file,
|
193
|
+
and recommend you check your diagram for missing models after it gets generated.
|
194
|
+
EOS
|
195
|
+
puts error_message
|
178
196
|
rescue TypeError
|
179
197
|
end
|
180
198
|
|
data/lib/rails_erd/config.rb
CHANGED
@@ -7,17 +7,21 @@ module RailsERD
|
|
7
7
|
|
8
8
|
attr_reader :options
|
9
9
|
|
10
|
-
def self.load
|
11
|
-
new.load
|
10
|
+
def self.load(extra_config_file=nil)
|
11
|
+
new.load extra_config_file
|
12
12
|
end
|
13
13
|
|
14
14
|
def initialize
|
15
15
|
@options = {}
|
16
16
|
end
|
17
17
|
|
18
|
-
def load
|
18
|
+
def load(extra_config_file=nil)
|
19
19
|
load_file(USER_WIDE_CONFIG_FILE)
|
20
20
|
load_file(CURRENT_CONFIG_FILE)
|
21
|
+
if extra_config_file
|
22
|
+
extra_config_path = File.expand_path(extra_config_file, Dir.pwd)
|
23
|
+
load_file(extra_config_path) if File.exist?(extra_config_path)
|
24
|
+
end
|
21
25
|
|
22
26
|
@options
|
23
27
|
end
|
@@ -77,6 +81,12 @@ module RailsERD
|
|
77
81
|
when :title
|
78
82
|
value.is_a?(String) ? value : !!value
|
79
83
|
|
84
|
+
# nil | <Hash>
|
85
|
+
when :fonts
|
86
|
+
if value
|
87
|
+
Hash(value).transform_keys(&:to_sym)
|
88
|
+
end
|
89
|
+
|
80
90
|
else
|
81
91
|
value
|
82
92
|
end
|
@@ -50,7 +50,7 @@ module RailsERD
|
|
50
50
|
|
51
51
|
NODE_WIDTH = 130 # @private :nodoc:
|
52
52
|
|
53
|
-
FONTS = Config.font_names_based_on_os
|
53
|
+
FONTS = Config.font_names_based_on_os.merge(RailsERD.options[:fonts])
|
54
54
|
|
55
55
|
# Default graph attributes.
|
56
56
|
GRAPH_ATTRIBUTES = {
|
@@ -86,6 +86,11 @@ module RailsERD
|
|
86
86
|
labeldistance: 1.8,
|
87
87
|
}
|
88
88
|
|
89
|
+
# Default cluster attributes.
|
90
|
+
CLUSTER_ATTRIBUTES = {
|
91
|
+
margin: "10,10"
|
92
|
+
}
|
93
|
+
|
89
94
|
module Simple
|
90
95
|
def entity_style(entity, attributes)
|
91
96
|
{}.tap do |options|
|
@@ -216,8 +221,10 @@ module RailsERD
|
|
216
221
|
each_entity do |entity, attributes|
|
217
222
|
if options[:cluster] && entity.namespace
|
218
223
|
cluster_name = "cluster_#{entity.namespace}"
|
224
|
+
cluster_options = CLUSTER_ATTRIBUTES.merge(label: entity.namespace)
|
219
225
|
cluster = graph.get_graph(cluster_name) ||
|
220
|
-
graph.add_graph(cluster_name,
|
226
|
+
graph.add_graph(cluster_name, cluster_options)
|
227
|
+
|
221
228
|
draw_cluster_node cluster, entity.name, entity_options(entity, attributes)
|
222
229
|
else
|
223
230
|
draw_node entity.name, entity_options(entity, attributes)
|
@@ -303,7 +310,12 @@ module RailsERD
|
|
303
310
|
end
|
304
311
|
|
305
312
|
def read_template(type)
|
306
|
-
|
313
|
+
template_text = File.read(File.expand_path("templates/#{NODE_LABEL_TEMPLATES[type]}", File.dirname(__FILE__)))
|
314
|
+
if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+
|
315
|
+
ERB.new(template_text, trim_mode: "<>")
|
316
|
+
else
|
317
|
+
ERB.new(template_text, nil, "<>")
|
318
|
+
end
|
307
319
|
end
|
308
320
|
end
|
309
321
|
end
|
data/lib/rails_erd/diagram.rb
CHANGED
@@ -125,7 +125,7 @@ module RailsERD
|
|
125
125
|
def generate
|
126
126
|
instance_eval(&callbacks[:setup])
|
127
127
|
if options.only_recursion_depth.present?
|
128
|
-
depth = options.only_recursion_depth.to_i
|
128
|
+
depth = options.only_recursion_depth.to_s.to_i
|
129
129
|
options[:only].dup.each do |class_name|
|
130
130
|
options[:only]+= recurse_into_relationships(@domain.entity_by_name(class_name), depth)
|
131
131
|
end
|
@@ -177,7 +177,7 @@ module RailsERD
|
|
177
177
|
|
178
178
|
def filtered_entities
|
179
179
|
@domain.entities.reject { |entity|
|
180
|
-
options.exclude.present? &&
|
180
|
+
options.exclude.present? && [options.exclude].flatten.map(&:to_sym).include?(entity.name.to_sym) or
|
181
181
|
options[:only].present? && entity.model && ![options[:only]].flatten.map(&:to_sym).include?(entity.name.to_sym) or
|
182
182
|
!options.inheritance && entity.specialized? or
|
183
183
|
!options.polymorphism && entity.generalized? or
|
@@ -78,8 +78,8 @@ module RailsERD
|
|
78
78
|
# relationship.
|
79
79
|
def foreign_key?
|
80
80
|
@domain.relationships_by_entity_name(@model.name).map(&:associations).flatten.map { |associaton|
|
81
|
-
associaton.send(Domain.foreign_key_method_name)
|
82
|
-
}.include?(name)
|
81
|
+
associaton.send(Domain.foreign_key_method_name).to_sym
|
82
|
+
}.include?(name.to_sym)
|
83
83
|
end
|
84
84
|
|
85
85
|
# Returns +true+ if this attribute is used for single table inheritance.
|
@@ -119,7 +119,7 @@ module RailsERD
|
|
119
119
|
# <tt>:decimal, :precision => 5, :scale => 2/tt>:: decimal (5,2)
|
120
120
|
# <tt>:boolean, :null => false</tt>:: boolean *
|
121
121
|
def type_description
|
122
|
-
type.to_s.tap do |desc|
|
122
|
+
type.to_s.dup.tap do |desc|
|
123
123
|
desc << " #{limit_description}" if limit_description
|
124
124
|
desc << " ∗" if mandatory? && !primary_key? # Add a hair space + low asterisk (Unicode characters)
|
125
125
|
desc << " U" if unique? && !primary_key? && !foreign_key? # Add U if unique but non-key
|
@@ -21,8 +21,7 @@ module RailsERD
|
|
21
21
|
private
|
22
22
|
|
23
23
|
def association_identity(association)
|
24
|
-
|
25
|
-
Set[identifier, association_owner(association), association_target(association)]
|
24
|
+
Set[association_owner(association), association_target(association)]
|
26
25
|
end
|
27
26
|
|
28
27
|
def association_identifier(association)
|
@@ -30,7 +30,14 @@ module RailsERD
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def abstract_from_models(domain, models)
|
33
|
-
models.select(&:abstract_class?)
|
33
|
+
abstract_classes = models.select(&:abstract_class?)
|
34
|
+
direct_descendants = if ActiveRecord.version >= Gem::Version.new("7.0.0")
|
35
|
+
abstract_classes.collect(&:subclasses)
|
36
|
+
else
|
37
|
+
abstract_classes.collect(&:direct_descendants)
|
38
|
+
end
|
39
|
+
|
40
|
+
direct_descendants.flatten.collect { |model|
|
34
41
|
new(domain, domain.entity_by_name(model.superclass.name), domain.entity_by_name(model.name))
|
35
42
|
}
|
36
43
|
end
|
data/lib/rails_erd/domain.rb
CHANGED
@@ -49,7 +49,13 @@ module RailsERD
|
|
49
49
|
# Returns the domain model name, which is the name of your Rails
|
50
50
|
# application or +nil+ outside of Rails.
|
51
51
|
def name
|
52
|
-
defined?
|
52
|
+
return unless defined?(Rails) && Rails.application
|
53
|
+
|
54
|
+
if Rails.application.class.respond_to?(:module_parent)
|
55
|
+
Rails.application.class.module_parent.name
|
56
|
+
else
|
57
|
+
Rails.application.class.parent.name
|
58
|
+
end
|
53
59
|
end
|
54
60
|
|
55
61
|
# Returns all entities of your domain model.
|
@@ -114,7 +120,32 @@ module RailsERD
|
|
114
120
|
end
|
115
121
|
|
116
122
|
def models
|
117
|
-
@models ||= @source_models
|
123
|
+
@models ||= @source_models
|
124
|
+
.reject { |model| tableless_rails_models.include?(model) }
|
125
|
+
.select { |model| check_model_validity(model) }
|
126
|
+
.reject { |model| check_habtm_model(model) }
|
127
|
+
end
|
128
|
+
|
129
|
+
# Returns Rails model classes defined in the app
|
130
|
+
def rails_models
|
131
|
+
%w(
|
132
|
+
ActionMailbox::InboundEmail
|
133
|
+
ActiveStorage::Attachment
|
134
|
+
ActiveStorage::Blob
|
135
|
+
ActiveStorage::VariantRecord
|
136
|
+
ActionText::RichText
|
137
|
+
ActionText::EncryptedRichText
|
138
|
+
).map{ |model| Object.const_get(model) rescue nil }.compact
|
139
|
+
end
|
140
|
+
|
141
|
+
def tableless_rails_models
|
142
|
+
@tableless_rails_models ||= begin
|
143
|
+
if defined? Rails
|
144
|
+
rails_models.reject{ |model| model.table_exists? }
|
145
|
+
else
|
146
|
+
[]
|
147
|
+
end
|
148
|
+
end
|
118
149
|
end
|
119
150
|
|
120
151
|
def associations
|
@@ -140,8 +171,7 @@ module RailsERD
|
|
140
171
|
association.check_validity!
|
141
172
|
|
142
173
|
if association.options[:polymorphic]
|
143
|
-
|
144
|
-
entity_by_name(entity_name) or raise "polymorphic interface #{entity_name} does not exist"
|
174
|
+
check_polymorphic_association_validity(association)
|
145
175
|
else
|
146
176
|
entity_name = association.klass.name # Raises NameError if the associated class cannot be found.
|
147
177
|
entity_by_name(entity_name) or raise "model #{entity_name} exists, but is not included in domain"
|
@@ -150,6 +180,17 @@ module RailsERD
|
|
150
180
|
warn "Ignoring invalid association #{association_description(association)} (#{e.message})"
|
151
181
|
end
|
152
182
|
|
183
|
+
def check_polymorphic_association_validity(association)
|
184
|
+
entity_name = association.class_name
|
185
|
+
entity = entity_by_name(entity_name)
|
186
|
+
|
187
|
+
if entity || (entity && entity.generalized?)
|
188
|
+
return entity
|
189
|
+
else
|
190
|
+
raise("polymorphic interface #{entity_name} does not exist")
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
153
194
|
def association_description(association)
|
154
195
|
"#{association.name.inspect} on #{association.active_record}"
|
155
196
|
end
|
data/lib/rails_erd/tasks.rake
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'graphviz/utils'
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
module ErdRakeHelper
|
4
|
+
def say(message)
|
5
|
+
puts message unless Rake.application.options.silent
|
6
|
+
end
|
5
7
|
end
|
6
8
|
|
7
9
|
namespace :erd do
|
@@ -19,12 +21,20 @@ namespace :erd do
|
|
19
21
|
when "true", "yes" then true
|
20
22
|
when "false", "no" then false
|
21
23
|
when /,/ then ENV[option].split(/\s*,\s*/)
|
22
|
-
|
24
|
+
when /^\d+$/ then ENV[option].to_i
|
25
|
+
else
|
26
|
+
if option == 'only'
|
27
|
+
[ENV[option]]
|
28
|
+
else
|
29
|
+
ENV[option].to_sym
|
30
|
+
end
|
23
31
|
end
|
24
32
|
end
|
25
33
|
end
|
26
34
|
|
27
35
|
task :load_models do
|
36
|
+
include ErdRakeHelper
|
37
|
+
|
28
38
|
say "Loading application environment..."
|
29
39
|
Rake::Task[:environment].invoke
|
30
40
|
|
@@ -49,12 +59,14 @@ namespace :erd do
|
|
49
59
|
end
|
50
60
|
|
51
61
|
task :generate => [:check_dependencies, :options, :load_models] do
|
62
|
+
include ErdRakeHelper
|
63
|
+
|
52
64
|
say "Generating Entity-Relationship Diagram for #{ActiveRecord::Base.descendants.length} models..."
|
53
65
|
|
54
66
|
require "rails_erd/diagram/graphviz"
|
55
67
|
file = RailsERD::Diagram::Graphviz.create
|
56
68
|
|
57
|
-
say "Done! Saved diagram to
|
69
|
+
say "Done! Saved diagram to ./#{file}"
|
58
70
|
end
|
59
71
|
end
|
60
72
|
|
data/lib/rails_erd/version.rb
CHANGED
data/lib/rails_erd.rb
CHANGED
data/test/test_helper.rb
CHANGED
@@ -1,15 +1,12 @@
|
|
1
1
|
require "rubygems"
|
2
2
|
require "bundler/setup"
|
3
|
+
require 'pry'
|
4
|
+
require 'pry-nav'
|
3
5
|
|
4
6
|
require "active_record"
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
require 'mocha/mini_test'
|
9
|
-
else
|
10
|
-
require "test/unit"
|
11
|
-
require 'mocha/test_unit'
|
12
|
-
end
|
8
|
+
require "minitest/autorun"
|
9
|
+
require 'mocha/minitest'
|
13
10
|
|
14
11
|
require "rails_erd/domain"
|
15
12
|
|
@@ -19,6 +16,14 @@ if ActiveSupport::TestCase.respond_to?(:test_order=)
|
|
19
16
|
ActiveSupport::TestCase.test_order = :random
|
20
17
|
end
|
21
18
|
|
19
|
+
# Patch to make Rails 6.1 work.
|
20
|
+
module Kernel
|
21
|
+
# class_eval on an object acts like singleton_class.class_eval.
|
22
|
+
def class_eval(*args, &block)
|
23
|
+
singleton_class.class_eval(*args, &block)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
22
27
|
class ActiveSupport::TestCase
|
23
28
|
include RailsERD
|
24
29
|
|
@@ -29,9 +34,11 @@ class ActiveSupport::TestCase
|
|
29
34
|
opts = if pk then { :primary_key => pk } else { :id => false } end
|
30
35
|
ActiveRecord::Schema.instance_eval do
|
31
36
|
suppress_messages do
|
32
|
-
|
33
|
-
|
34
|
-
|
37
|
+
unless ActiveRecord::Base.connection.table_exists?(table)
|
38
|
+
create_table table, **opts do |t|
|
39
|
+
columns.each do |column, type|
|
40
|
+
t.send type, column
|
41
|
+
end
|
35
42
|
end
|
36
43
|
end
|
37
44
|
end
|
@@ -42,7 +49,8 @@ class ActiveSupport::TestCase
|
|
42
49
|
def add_column(*args)
|
43
50
|
ActiveRecord::Schema.instance_eval do
|
44
51
|
suppress_messages do
|
45
|
-
|
52
|
+
opts = args.slice!(3) || {}
|
53
|
+
add_column(*args, **opts)
|
46
54
|
end
|
47
55
|
end
|
48
56
|
ActiveRecord::Base.clear_cache!
|
@@ -75,8 +83,9 @@ class ActiveSupport::TestCase
|
|
75
83
|
superklass = args.first.kind_of?(Class) ? args.shift : ActiveRecord::Base
|
76
84
|
columns = args.first || {}
|
77
85
|
klass = Object.const_set name.to_sym, Class.new(superklass)
|
86
|
+
|
78
87
|
if superklass == ActiveRecord::Base || superklass.abstract_class?
|
79
|
-
create_table Object.const_get(name.to_sym).table_name, columns, Object.const_get(name.to_sym).primary_key
|
88
|
+
create_table Object.const_get(name.to_sym).table_name, columns, Object.const_get(name.to_sym).primary_key
|
80
89
|
end
|
81
90
|
klass.class_eval(&block) if block_given?
|
82
91
|
Object.const_get(name.to_sym)
|
@@ -173,6 +182,11 @@ class ActiveSupport::TestCase
|
|
173
182
|
|
174
183
|
parts[1..-1].inject([[Object, parts.first.to_sym]]) do |pairs,string|
|
175
184
|
last_parent, last_child = pairs.last
|
185
|
+
# Fixes for Rails 6. No idea if this is actually correct as I can't decipher what the heck is going on in this
|
186
|
+
# code.
|
187
|
+
if last_child == :ActiveRecord || last_child == :primary
|
188
|
+
break []
|
189
|
+
end
|
176
190
|
|
177
191
|
break pairs unless last_parent.const_defined?(last_child)
|
178
192
|
|
@@ -196,11 +210,23 @@ class ActiveSupport::TestCase
|
|
196
210
|
model.reset_column_information
|
197
211
|
remove_fully_qualified_constant(model.name)
|
198
212
|
end
|
213
|
+
|
199
214
|
tables_and_views.each do |table|
|
200
215
|
ActiveRecord::Base.connection.drop_table table
|
201
216
|
end
|
202
|
-
|
203
|
-
|
217
|
+
|
218
|
+
if ActiveRecord.version >= Gem::Version.new("7.0.0")
|
219
|
+
ActiveSupport::DescendantsTracker.clear(ActiveRecord::Base.subclasses)
|
220
|
+
elsif ActiveRecord.version >= Gem::Version.new("6.0.0.rc1")
|
221
|
+
cv = ActiveSupport::DescendantsTracker.class_variable_get(:@@direct_descendants)
|
222
|
+
cv.delete(ActiveRecord::Base)
|
223
|
+
ActiveSupport::DescendantsTracker.class_variable_set(:@@direct_descendants, cv)
|
224
|
+
ActiveSupport::Dependencies::Reference.clear!
|
225
|
+
else
|
226
|
+
ActiveRecord::Base.direct_descendants.clear
|
227
|
+
ActiveSupport::Dependencies::Reference.clear!
|
228
|
+
end
|
229
|
+
|
204
230
|
ActiveRecord::Base.clear_cache!
|
205
231
|
end
|
206
232
|
end
|
data/test/unit/attribute_test.rb
CHANGED
@@ -3,9 +3,9 @@ require File.expand_path("../test_helper", File.dirname(__FILE__))
|
|
3
3
|
|
4
4
|
class AttributeTest < ActiveSupport::TestCase
|
5
5
|
def with_native_limit(type, new_limit)
|
6
|
-
ActiveRecord::Base.connection.class_eval do
|
6
|
+
ActiveRecord::Base.connection.singleton_class.class_eval do
|
7
7
|
undef :native_database_types
|
8
|
-
define_method
|
8
|
+
define_method(:native_database_types) do
|
9
9
|
super().tap do |types|
|
10
10
|
types[type][:limit] = new_limit
|
11
11
|
end
|
@@ -13,9 +13,9 @@ class AttributeTest < ActiveSupport::TestCase
|
|
13
13
|
end
|
14
14
|
yield
|
15
15
|
ensure
|
16
|
-
ActiveRecord::Base.connection.class_eval do
|
16
|
+
ActiveRecord::Base.connection.singleton_class.class_eval do
|
17
17
|
undef :native_database_types
|
18
|
-
define_method
|
18
|
+
define_method(:native_database_types) do
|
19
19
|
super()
|
20
20
|
end
|
21
21
|
end
|
@@ -266,14 +266,14 @@ class AttributeTest < ActiveSupport::TestCase
|
|
266
266
|
end
|
267
267
|
|
268
268
|
test "limit should return nil for oddball column types that misuse the limit attribute" do
|
269
|
-
create_model "Business", :location => :integer
|
270
|
-
|
271
|
-
attribute.column.class_eval do
|
272
|
-
define_method :limit do
|
269
|
+
create_model "Business", :location => :integer do
|
270
|
+
define_singleton_method :limit do
|
273
271
|
# https://github.com/voormedia/rails-erd/issues/21
|
274
272
|
{ :srid => 4326, :type => "point", :geographic => true }
|
275
273
|
end
|
276
274
|
end
|
275
|
+
|
276
|
+
attribute = create_attribute(Business, "location")
|
277
277
|
assert_nil attribute.limit
|
278
278
|
end
|
279
279
|
|
@@ -306,13 +306,12 @@ class AttributeTest < ActiveSupport::TestCase
|
|
306
306
|
end
|
307
307
|
|
308
308
|
test "scale should return nil for oddball column types that misuse the scale attribute" do
|
309
|
-
create_model "Kobold", :size => :integer
|
310
|
-
attribute = create_attribute(Kobold, "size")
|
311
|
-
attribute.column.class_eval do
|
309
|
+
create_model "Kobold", :size => :integer do
|
312
310
|
define_method :scale do
|
313
311
|
1..5
|
314
312
|
end
|
315
313
|
end
|
314
|
+
attribute = create_attribute(Kobold, "size")
|
316
315
|
assert_nil attribute.scale
|
317
316
|
end
|
318
317
|
end
|
data/test/unit/config_test.rb
CHANGED
@@ -61,6 +61,29 @@ class ConfigTest < ActiveSupport::TestCase
|
|
61
61
|
assert_equal expected_hash, RailsERD::Config.load
|
62
62
|
end
|
63
63
|
|
64
|
+
test "load_config_file should return a hash from the configured config file when a new config file is given as an argument" do
|
65
|
+
set_local_config_file_to("erdconfig.another_example")
|
66
|
+
|
67
|
+
expected_hash = {
|
68
|
+
attributes: [:content, :foreign_key, :inheritance, :false],
|
69
|
+
disconnected: true,
|
70
|
+
filename: "erd",
|
71
|
+
filetype: :pdf,
|
72
|
+
indirect: true,
|
73
|
+
inheritance: false,
|
74
|
+
markup: true,
|
75
|
+
notation: :simple,
|
76
|
+
orientation: "horizontal",
|
77
|
+
polymorphism: false,
|
78
|
+
warn: true,
|
79
|
+
title: "sample title",
|
80
|
+
exclude: [],
|
81
|
+
only: []
|
82
|
+
}
|
83
|
+
|
84
|
+
assert_equal expected_hash, RailsERD::Config.load("test/support_files/erdconfig.example")
|
85
|
+
end
|
86
|
+
|
64
87
|
test "load_config_gile should return a hash from CURRENT_CONFIG_FILE overriding USER_WIDE_CONFIG_FILE when both of them exist." do
|
65
88
|
set_user_config_file_to("erdconfig.example")
|
66
89
|
set_local_config_file_to("erdconfig.another_example")
|
@@ -92,6 +115,12 @@ class ConfigTest < ActiveSupport::TestCase
|
|
92
115
|
assert_equal [:content, :primary_keys], normalize_value(:attributes, ["content", "primary_keys"])
|
93
116
|
end
|
94
117
|
|
118
|
+
test "normalize_value should return hash with symbol keys when key is :fonts and value is a hash." do
|
119
|
+
fonts_value = { "normal" => "Arial", "bold" => "Arial Bold", "italic" => "Arial Italic" }
|
120
|
+
expected = {:normal => "Arial", :bold => "Arial Bold", :italic => "Arial Italic"}
|
121
|
+
assert_equal expected, normalize_value(:fonts, fonts_value)
|
122
|
+
end
|
123
|
+
|
95
124
|
def normalize_value(key, value)
|
96
125
|
RailsERD::Config.new.send(:normalize_value, key, value)
|
97
126
|
end
|
data/test/unit/diagram_test.rb
CHANGED
@@ -136,6 +136,15 @@ class DiagramTest < ActiveSupport::TestCase
|
|
136
136
|
assert_equal [Book], retrieve_entities(:exclude => [:Author, :Editor]).map(&:model)
|
137
137
|
end
|
138
138
|
|
139
|
+
test "generate should filter excluded polymorphic entities" do
|
140
|
+
create_model "Cannon"
|
141
|
+
create_model "Galleon" do
|
142
|
+
has_many :cannons, as: :defensible
|
143
|
+
end
|
144
|
+
assert_equal ["Cannon", "Galleon"], retrieve_entities(polymorphism: true, exclude: :Defensible).map(&:name)
|
145
|
+
end
|
146
|
+
|
147
|
+
|
139
148
|
test "generate should include only specified entity" do
|
140
149
|
create_model "Book"
|
141
150
|
create_model "Author"
|
data/test/unit/domain_test.rb
CHANGED
@@ -127,13 +127,21 @@ class DomainTest < ActiveSupport::TestCase
|
|
127
127
|
end
|
128
128
|
|
129
129
|
test "relationships should count relationship between same models with distinct foreign key seperately" do
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
130
|
+
# TODO: Once we drop Rails 3.2 support, we _should_ be able to drop the
|
131
|
+
# :respond_to? check
|
132
|
+
#
|
133
|
+
if respond_to? :skip
|
134
|
+
skip("multiple edges between the same objects can cause segfaults in some versions of Graphviz")
|
135
|
+
|
136
|
+
create_model "Foo", :bar => :references, :special_bar => :references do
|
137
|
+
belongs_to :bar
|
138
|
+
end
|
139
|
+
create_model "Bar" do
|
140
|
+
has_many :foos, :foreign_key => :special_bar_id
|
141
|
+
end
|
142
|
+
|
143
|
+
assert_equal [Domain::Relationship] * 2, Domain.generate.relationships.collect(&:class)
|
135
144
|
end
|
136
|
-
assert_equal [Domain::Relationship] * 2, Domain.generate.relationships.collect(&:class)
|
137
145
|
end
|
138
146
|
|
139
147
|
test "relationships should use model name first in alphabet as source for many to many relationships" do
|
@@ -275,4 +283,14 @@ class DomainTest < ActiveSupport::TestCase
|
|
275
283
|
end
|
276
284
|
assert_match(/Ignoring invalid model Foo \(table foos does not exist\)/, output)
|
277
285
|
end
|
286
|
+
|
287
|
+
test "entities should not output a warning when a Rails model table does not exist" do
|
288
|
+
module ActionMailbox; end
|
289
|
+
|
290
|
+
Object.const_set :InboundEmail, ActionMailbox
|
291
|
+
output = collect_stdout do
|
292
|
+
Domain.generate.entities
|
293
|
+
end
|
294
|
+
assert_equal "", output
|
295
|
+
end
|
278
296
|
end
|
data/test/unit/graphviz_test.rb
CHANGED
@@ -186,6 +186,16 @@ class GraphvizTest < ActiveSupport::TestCase
|
|
186
186
|
assert_equal '"Domain model\n\n"', diagram.graph.graph[:label].to_s
|
187
187
|
end
|
188
188
|
|
189
|
+
test "generate should use default value for fontname attribute" do
|
190
|
+
create_simple_domain
|
191
|
+
assert_equal "\"#{RailsERD::Config.font_names_based_on_os[:bold]}\"", diagram.graph.graph[:fontname].to_s
|
192
|
+
end
|
193
|
+
|
194
|
+
test "generate should add set value for fontname attribute" do
|
195
|
+
create_simple_domain
|
196
|
+
assert_equal '"Arial Bold"', diagram(fonts: {bold: "Arial Bold"}).graph.graph[:fontname].to_s
|
197
|
+
end
|
198
|
+
|
189
199
|
test "generate should add default value for splines attribute" do
|
190
200
|
create_simple_domain
|
191
201
|
assert_equal '"spline"', diagram.graph.graph[:splines].to_s
|
@@ -304,13 +314,21 @@ class GraphvizTest < ActiveSupport::TestCase
|
|
304
314
|
end
|
305
315
|
|
306
316
|
test "generate should create edge for each relationship" do
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
317
|
+
# TODO: Once we drop Rails 3.2 support, we _should_ be able to drop the
|
318
|
+
# :respond_to? check
|
319
|
+
#
|
320
|
+
if respond_to? :skip
|
321
|
+
skip("multiple edges between the same objects can cause segfaults in some versions of Graphviz")
|
322
|
+
|
323
|
+
create_model "Foo", :bar => :references do
|
324
|
+
belongs_to :bar
|
325
|
+
end
|
326
|
+
create_model "Bar", :foo => :references do
|
327
|
+
belongs_to :foo
|
328
|
+
end
|
329
|
+
|
330
|
+
assert_equal [["m_Bar", "m_Foo"], ["m_Foo", "m_Bar"]], find_dot_node_pairs(diagram).sort
|
312
331
|
end
|
313
|
-
assert_equal [["m_Bar", "m_Foo"], ["m_Foo", "m_Bar"]], find_dot_node_pairs(diagram).sort
|
314
332
|
end
|
315
333
|
|
316
334
|
test "generate should create edge to polymorphic entity if polymorphism is true" do
|
data/test/unit/rake_task_test.rb
CHANGED
@@ -173,4 +173,22 @@ Error occurred while loading application: FooBar (RuntimeError)
|
|
173
173
|
Rake::Task["erd:options"].execute
|
174
174
|
assert_equal %w[content timestamps], RailsERD.options.attributes
|
175
175
|
end
|
176
|
+
|
177
|
+
test "options task should set known integer command line options when value is only digits" do
|
178
|
+
ENV["only_recursion_depth"] = "2"
|
179
|
+
Rake::Task["erd:options"].execute
|
180
|
+
assert_equal 2, RailsERD.options.only_recursion_depth
|
181
|
+
end
|
182
|
+
|
183
|
+
test "options task sets known command line options as symbols when not boolean or numeric" do
|
184
|
+
ENV["only_recursion_depth"] = "test"
|
185
|
+
Rake::Task["erd:options"].execute
|
186
|
+
assert_equal :test, RailsERD.options.only_recursion_depth
|
187
|
+
end
|
188
|
+
|
189
|
+
test "options task should set single parameter to only as array xxx" do
|
190
|
+
ENV["only"] = "model"
|
191
|
+
Rake::Task["erd:options"].execute
|
192
|
+
assert_equal ["model"], RailsERD.options.only
|
193
|
+
end
|
176
194
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails-erd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rolf Timmermans
|
8
8
|
- Kerri Miller
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2022-08-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -17,28 +17,28 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - ">="
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: '
|
20
|
+
version: '4.2'
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: '
|
27
|
+
version: '4.2'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: activesupport
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
32
|
- - ">="
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: '
|
34
|
+
version: '4.2'
|
35
35
|
type: :runtime
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
39
|
- - ">="
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version: '
|
41
|
+
version: '4.2'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: ruby-graphviz
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -67,6 +67,34 @@ dependencies:
|
|
67
67
|
- - "~>"
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: 0.2.0
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: pry
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: pry-nav
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
70
98
|
description: Automatically generate an entity-relationship diagram (ERD) for your
|
71
99
|
Rails models.
|
72
100
|
email:
|
@@ -119,7 +147,7 @@ homepage: https://github.com/voormedia/rails-erd
|
|
119
147
|
licenses:
|
120
148
|
- MIT
|
121
149
|
metadata: {}
|
122
|
-
post_install_message:
|
150
|
+
post_install_message:
|
123
151
|
rdoc_options: []
|
124
152
|
require_paths:
|
125
153
|
- lib
|
@@ -127,16 +155,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
127
155
|
requirements:
|
128
156
|
- - ">="
|
129
157
|
- !ruby/object:Gem::Version
|
130
|
-
version:
|
158
|
+
version: '2.2'
|
131
159
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
132
160
|
requirements:
|
133
161
|
- - ">="
|
134
162
|
- !ruby/object:Gem::Version
|
135
163
|
version: '0'
|
136
164
|
requirements: []
|
137
|
-
|
138
|
-
|
139
|
-
signing_key:
|
165
|
+
rubygems_version: 3.3.15
|
166
|
+
signing_key:
|
140
167
|
specification_version: 4
|
141
168
|
summary: Entity-relationship diagram for your Rails models.
|
142
169
|
test_files:
|