rails-erd 0.3.0 → 0.4.0
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.
- data/.gitignore +1 -0
- data/CHANGES.rdoc +17 -1
- data/Gemfile +3 -2
- data/Gemfile.lock +8 -4
- data/README.md +60 -0
- data/Rakefile +10 -50
- data/VERSION +1 -1
- data/lib/rails_erd.rb +28 -1
- data/lib/rails_erd/diagram.rb +66 -33
- data/lib/rails_erd/diagram/graphviz.rb +123 -92
- data/lib/rails_erd/diagram/templates/node.erb +2 -2
- data/lib/rails_erd/domain.rb +51 -23
- data/lib/rails_erd/domain/attribute.rb +102 -0
- data/lib/rails_erd/domain/entity.rb +102 -0
- data/lib/rails_erd/domain/relationship.rb +189 -0
- data/lib/rails_erd/domain/relationship/cardinality.rb +118 -0
- data/lib/rails_erd/domain/specialization.rb +58 -0
- data/lib/rails_erd/railtie.rb +1 -1
- data/rails-erd.gemspec +19 -16
- data/test/test_helper.rb +21 -5
- data/test/unit/attribute_test.rb +35 -8
- data/test/unit/cardinality_test.rb +41 -35
- data/test/unit/diagram_test.rb +130 -43
- data/test/unit/domain_test.rb +131 -8
- data/test/unit/entity_test.rb +150 -46
- data/test/unit/graphviz_test.rb +52 -14
- data/test/unit/rake_task_test.rb +2 -2
- data/test/unit/relationship_test.rb +73 -24
- data/test/unit/specialization_test.rb +57 -0
- metadata +15 -13
- data/README.rdoc +0 -51
- data/lib/rails_erd/attribute.rb +0 -95
- data/lib/rails_erd/entity.rb +0 -73
- data/lib/rails_erd/relationship.rb +0 -177
- data/lib/rails_erd/relationship/cardinality.rb +0 -118
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
7
|
+
- 4
|
8
8
|
- 0
|
9
|
-
version: 0.
|
9
|
+
version: 0.4.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Rolf Timmermans
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-10-
|
17
|
+
date: 2010-10-12 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -28,8 +28,7 @@ dependencies:
|
|
28
28
|
segments:
|
29
29
|
- 3
|
30
30
|
- 0
|
31
|
-
|
32
|
-
version: 3.0.0
|
31
|
+
version: "3.0"
|
33
32
|
type: :runtime
|
34
33
|
version_requirements: *id001
|
35
34
|
- !ruby/object:Gem::Dependency
|
@@ -57,8 +56,8 @@ dependencies:
|
|
57
56
|
segments:
|
58
57
|
- 0
|
59
58
|
- 9
|
60
|
-
-
|
61
|
-
version: 0.9.
|
59
|
+
- 18
|
60
|
+
version: 0.9.18
|
62
61
|
type: :runtime
|
63
62
|
version_requirements: *id003
|
64
63
|
- !ruby/object:Gem::Dependency
|
@@ -82,27 +81,28 @@ extensions: []
|
|
82
81
|
|
83
82
|
extra_rdoc_files:
|
84
83
|
- LICENSE
|
85
|
-
- README.
|
84
|
+
- README.md
|
86
85
|
files:
|
87
86
|
- .gitignore
|
88
87
|
- CHANGES.rdoc
|
89
88
|
- Gemfile
|
90
89
|
- Gemfile.lock
|
91
90
|
- LICENSE
|
92
|
-
- README.
|
91
|
+
- README.md
|
93
92
|
- Rakefile
|
94
93
|
- VERSION
|
95
94
|
- lib/rails-erd.rb
|
96
95
|
- lib/rails_erd.rb
|
97
|
-
- lib/rails_erd/attribute.rb
|
98
96
|
- lib/rails_erd/diagram.rb
|
99
97
|
- lib/rails_erd/diagram/graphviz.rb
|
100
98
|
- lib/rails_erd/diagram/templates/node.erb
|
101
99
|
- lib/rails_erd/domain.rb
|
102
|
-
- lib/rails_erd/
|
100
|
+
- lib/rails_erd/domain/attribute.rb
|
101
|
+
- lib/rails_erd/domain/entity.rb
|
102
|
+
- lib/rails_erd/domain/relationship.rb
|
103
|
+
- lib/rails_erd/domain/relationship/cardinality.rb
|
104
|
+
- lib/rails_erd/domain/specialization.rb
|
103
105
|
- lib/rails_erd/railtie.rb
|
104
|
-
- lib/rails_erd/relationship.rb
|
105
|
-
- lib/rails_erd/relationship/cardinality.rb
|
106
106
|
- lib/rails_erd/tasks.rake
|
107
107
|
- rails-erd.gemspec
|
108
108
|
- test/test_helper.rb
|
@@ -114,6 +114,7 @@ files:
|
|
114
114
|
- test/unit/graphviz_test.rb
|
115
115
|
- test/unit/rake_task_test.rb
|
116
116
|
- test/unit/relationship_test.rb
|
117
|
+
- test/unit/specialization_test.rb
|
117
118
|
has_rdoc: true
|
118
119
|
homepage: http://rails-erd.rubyforge.org/
|
119
120
|
licenses: []
|
@@ -156,3 +157,4 @@ test_files:
|
|
156
157
|
- test/unit/graphviz_test.rb
|
157
158
|
- test/unit/rake_task_test.rb
|
158
159
|
- test/unit/relationship_test.rb
|
160
|
+
- test/unit/specialization_test.rb
|
data/README.rdoc
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
= Rails ERD - Generate Entity-Relationship Diagrams for Rails applications
|
2
|
-
|
3
|
-
{Rails ERD}[http://rails-erd.rubyforge.org/] is a Rails plugin that allows
|
4
|
-
you to easily generate a diagram based on your Active Record models. The
|
5
|
-
diagram gives an overview of how your models are related. Having a diagram
|
6
|
-
that describes your models is perfect documentation for your application.
|
7
|
-
|
8
|
-
The second goal of Rails ERD is to provide you with a tool to inspect your
|
9
|
-
application's domain model. If you don't like the default output, it is very
|
10
|
-
easy to use the API to build your own diagrams.
|
11
|
-
|
12
|
-
Rails ERD was created specifically for Rails 3. It uses Active Record's
|
13
|
-
built-in reflection capabilities to figure out how your models are associated.
|
14
|
-
|
15
|
-
== Preview
|
16
|
-
|
17
|
-
Here's an example entity-relationship diagram that was generated by Rails ERD:
|
18
|
-
|
19
|
-
http://rails-erd.rubyforge.org/examples/event-forms.png
|
20
|
-
|
21
|
-
== Learn more
|
22
|
-
|
23
|
-
Homepage:
|
24
|
-
http://rails-erd.rubyforge.org/
|
25
|
-
|
26
|
-
Diagram gallery:
|
27
|
-
http://rails-erd.rubyforge.org/gallery.html
|
28
|
-
|
29
|
-
Installation instructions:
|
30
|
-
http://rails-erd.rubyforge.org/install.html
|
31
|
-
|
32
|
-
Internal API documentation:
|
33
|
-
http://rails-erd.rubyforge.org/doc/
|
34
|
-
|
35
|
-
Source code at Github:
|
36
|
-
http://github.com/voormedia/rails-erd
|
37
|
-
|
38
|
-
== About Rails ERD
|
39
|
-
|
40
|
-
Author: Rolf Timmermans (r.timmermans <i>at</i> voormedia.com)
|
41
|
-
|
42
|
-
Copyright 2010 Voormedia B.V.
|
43
|
-
|
44
|
-
== License
|
45
|
-
|
46
|
-
Rails ERD is released under the MIT license. See the LICENSE.
|
47
|
-
|
48
|
-
== Credits
|
49
|
-
|
50
|
-
Rails ERD depends on the Ruby-Graphviz library to generate diagrams:
|
51
|
-
http://github.com/glejeune/Ruby-Graphviz/
|
data/lib/rails_erd/attribute.rb
DELETED
@@ -1,95 +0,0 @@
|
|
1
|
-
# -*- encoding: utf-8
|
2
|
-
module RailsERD
|
3
|
-
# Describes an entity's attribute. Attributes correspond directly to
|
4
|
-
# database columns.
|
5
|
-
class Attribute
|
6
|
-
TIMESTAMP_NAMES = %w{created_at created_on updated_at updated_on} # @private :nodoc:
|
7
|
-
|
8
|
-
class << self
|
9
|
-
def from_model(domain, model) # @private :nodoc:
|
10
|
-
model.arel_table.columns.collect { |column| Attribute.new(domain, model, column) }.sort
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
attr_reader :column # @private :nodoc:
|
15
|
-
|
16
|
-
def initialize(domain, model, column) # @private :nodoc:
|
17
|
-
@domain, @model, @column = domain, model, column
|
18
|
-
end
|
19
|
-
|
20
|
-
# The name of the attribute, equal to the column name.
|
21
|
-
def name
|
22
|
-
column.name
|
23
|
-
end
|
24
|
-
|
25
|
-
# The type of the attribute, equal to the Rails migration type. Can be any
|
26
|
-
# of +:string+, +:integer+, +:boolean+, +:text+, etc.
|
27
|
-
def type
|
28
|
-
column.type
|
29
|
-
end
|
30
|
-
|
31
|
-
# Returns +true+ if this attribute has no special meaning, that is, if it
|
32
|
-
# is not a primary key, foreign key, or timestamp.
|
33
|
-
def regular?
|
34
|
-
!primary_key? and !foreign_key? and !timestamp?
|
35
|
-
end
|
36
|
-
|
37
|
-
# Returns +true+ if this attribute is mandatory. Mandatory attributes
|
38
|
-
# either have a presence validation (+validates_presence_of+), or have a
|
39
|
-
# <tt>NOT NULL</tt> database constraint.
|
40
|
-
def mandatory?
|
41
|
-
!column.null or @model.validators_on(name).map(&:kind).include?(:presence)
|
42
|
-
end
|
43
|
-
|
44
|
-
# Returns +true+ if this attribute is the primary key of the entity.
|
45
|
-
def primary_key?
|
46
|
-
@model.arel_table.primary_key == name
|
47
|
-
end
|
48
|
-
|
49
|
-
# Returns +true+ if this attribute is used as a foreign key for any
|
50
|
-
# relationship.
|
51
|
-
def foreign_key?
|
52
|
-
@domain.relationships_for(@model).map(&:associations).flatten.map(&:primary_key_name).include?(name)
|
53
|
-
end
|
54
|
-
|
55
|
-
# Returns +true+ if this attribute is one of the standard 'magic' Rails
|
56
|
-
# timestamp columns, being +created_at+, +updated_at+, +created_on+ or
|
57
|
-
# +updated_on+.
|
58
|
-
def timestamp?
|
59
|
-
TIMESTAMP_NAMES.include? name
|
60
|
-
end
|
61
|
-
|
62
|
-
def <=>(other) # @private :nodoc:
|
63
|
-
name <=> other.name
|
64
|
-
end
|
65
|
-
|
66
|
-
def inspect # @private :nodoc:
|
67
|
-
"#<#{self.class.name}:0x%.14x @column=#{name.inspect} @type=#{type.inspect}>" % (object_id << 1)
|
68
|
-
end
|
69
|
-
|
70
|
-
def to_s # @private :nodoc:
|
71
|
-
name
|
72
|
-
end
|
73
|
-
|
74
|
-
# Returns a description of the attribute type. If the attribute has
|
75
|
-
# a non-standard limit or if it is mandatory, this information is included.
|
76
|
-
#
|
77
|
-
# Example output:
|
78
|
-
# <tt>:integer</tt>:: integer
|
79
|
-
# <tt>:string, :limit => 255</tt>:: string
|
80
|
-
# <tt>:string, :limit => 128</tt>:: string (128)
|
81
|
-
# <tt>:boolean, :null => false</tt>:: boolean *
|
82
|
-
def type_description
|
83
|
-
type.to_s.tap do |desc|
|
84
|
-
desc << " (#{limit})" if limit
|
85
|
-
desc << " ∗" if mandatory? # Add a hair space + low asterisk (Unicode characters).
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
# Returns any non-standard limit for this attribute. If a column has no
|
90
|
-
# limit or uses a default database limit, this method returns +nil+.
|
91
|
-
def limit
|
92
|
-
column.limit if column.limit != @model.connection.native_database_types[type][:limit]
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
data/lib/rails_erd/entity.rb
DELETED
@@ -1,73 +0,0 @@
|
|
1
|
-
module RailsERD
|
2
|
-
# Entities represent your Active Record models. Entities may be connected
|
3
|
-
# to other entities.
|
4
|
-
class Entity
|
5
|
-
class << self
|
6
|
-
def from_models(domain, models) # @private :nodoc:
|
7
|
-
models.collect { |model| new domain, model }.sort
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
# The domain in which this entity resides.
|
12
|
-
attr_reader :domain
|
13
|
-
|
14
|
-
# The Active Record model that this entity corresponds to.
|
15
|
-
attr_reader :model
|
16
|
-
|
17
|
-
def initialize(domain, model) # @private :nodoc:
|
18
|
-
@domain, @model = domain, model
|
19
|
-
end
|
20
|
-
|
21
|
-
# Returns an array of attributes for this entity.
|
22
|
-
def attributes
|
23
|
-
@attributes ||= Attribute.from_model @domain, @model
|
24
|
-
end
|
25
|
-
|
26
|
-
# Returns an array of all relationships that this entity has with other
|
27
|
-
# entities in the domain model.
|
28
|
-
def relationships
|
29
|
-
@domain.relationships_for(@model)
|
30
|
-
end
|
31
|
-
|
32
|
-
# Returns the parent entity, if this entity is a descendant.
|
33
|
-
def parent
|
34
|
-
@domain.entity_for(@model.superclass) if descendant?
|
35
|
-
end
|
36
|
-
|
37
|
-
# Returns +true+ if this entity has any relationships with other models,
|
38
|
-
# +false+ otherwise.
|
39
|
-
def connected?
|
40
|
-
relationships.any?
|
41
|
-
end
|
42
|
-
|
43
|
-
# Returns +true+ if this entity has no relationships with any other models,
|
44
|
-
# +false+ otherwise. Opposite of +connected?+.
|
45
|
-
def disconnected?
|
46
|
-
relationships.none?
|
47
|
-
end
|
48
|
-
|
49
|
-
# Returns +true+ if this entity descends from another entity, and is
|
50
|
-
# represented in the same table as its parent.
|
51
|
-
def descendant?
|
52
|
-
!@model.descends_from_active_record?
|
53
|
-
end
|
54
|
-
|
55
|
-
# Returns the name of this entity, which is the class name of the
|
56
|
-
# corresponding model.
|
57
|
-
def name
|
58
|
-
model.name
|
59
|
-
end
|
60
|
-
|
61
|
-
def inspect # @private :nodoc:
|
62
|
-
"#<#{self.class}:0x%.14x @model=#{name}>" % (object_id << 1)
|
63
|
-
end
|
64
|
-
|
65
|
-
def to_s # @private :nodoc:
|
66
|
-
name
|
67
|
-
end
|
68
|
-
|
69
|
-
def <=>(other) # @private :nodoc:
|
70
|
-
self.name <=> other.name
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
@@ -1,177 +0,0 @@
|
|
1
|
-
require "rails_erd/relationship/cardinality"
|
2
|
-
|
3
|
-
module RailsERD
|
4
|
-
# Describes a relationship between two entities. A relationship is detected
|
5
|
-
# based on Active Record associations. One relationship may represent more
|
6
|
-
# than one association, however. Related associations are grouped together.
|
7
|
-
# Associations are related if they share the same foreign key, or the same
|
8
|
-
# join table in the case of many-to-many associations.
|
9
|
-
class Relationship
|
10
|
-
N = Cardinality::N
|
11
|
-
|
12
|
-
class << self
|
13
|
-
def from_associations(domain, associations) # @private :nodoc:
|
14
|
-
assoc_groups = associations.group_by { |assoc| association_identity(assoc) }
|
15
|
-
assoc_groups.collect { |_, assoc_group| Relationship.new(domain, assoc_group.to_a) }
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def association_identity(assoc)
|
21
|
-
identifier = assoc.options[:join_table] || assoc.primary_key_name.to_s
|
22
|
-
Set[identifier, assoc.active_record, assoc.klass]
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
# The domain in which this relationship is defined.
|
27
|
-
attr_reader :domain
|
28
|
-
|
29
|
-
# The source entity. It corresponds to the model that has defined a
|
30
|
-
# +has_one+ or +has_many+ association with the other model.
|
31
|
-
attr_reader :source
|
32
|
-
|
33
|
-
# The destination entity. It corresponds to the model that has defined
|
34
|
-
# a +belongs_to+ association with the other model.
|
35
|
-
attr_reader :destination
|
36
|
-
|
37
|
-
delegate :one_to_one?, :one_to_many?, :many_to_many?, :source_optional?,
|
38
|
-
:destination_optional?, :to => :cardinality
|
39
|
-
|
40
|
-
def initialize(domain, associations) # @private :nodoc:
|
41
|
-
@domain = domain
|
42
|
-
@reverse_associations, @forward_associations = *unless any_habtm?(associations)
|
43
|
-
associations.partition(&:belongs_to?)
|
44
|
-
else
|
45
|
-
# Many-to-many associations don't have a clearly defined direction.
|
46
|
-
# We sort by name and use the first model as the source.
|
47
|
-
source = associations.first.active_record
|
48
|
-
associations.partition { |association| association.active_record == source }
|
49
|
-
end
|
50
|
-
|
51
|
-
assoc = @forward_associations.first || @reverse_associations.first
|
52
|
-
@source, @destination = @domain.entity_for(assoc.active_record), @domain.entity_for(assoc.klass)
|
53
|
-
@source, @destination = @destination, @source if assoc.belongs_to?
|
54
|
-
end
|
55
|
-
|
56
|
-
# Returns all Active Record association objects that describe this
|
57
|
-
# relationship.
|
58
|
-
def associations
|
59
|
-
@forward_associations + @reverse_associations
|
60
|
-
end
|
61
|
-
|
62
|
-
# Returns the cardinality of this relationship.
|
63
|
-
def cardinality
|
64
|
-
@cardinality ||= begin
|
65
|
-
reverse_max = any_habtm?(associations) ? N : 1
|
66
|
-
forward_range = associations_range(@source.model, @forward_associations, N)
|
67
|
-
reverse_range = associations_range(@destination.model, @reverse_associations, reverse_max)
|
68
|
-
Cardinality.new(reverse_range, forward_range)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
# Indicates if a relationship is indirect, that is, if it is defined
|
73
|
-
# through other relationships. Indirect relationships are created in
|
74
|
-
# Rails with <tt>has_many :through</tt> or <tt>has_one :through</tt>
|
75
|
-
# association macros.
|
76
|
-
def indirect?
|
77
|
-
!@forward_associations.empty? and @forward_associations.all?(&:through_reflection)
|
78
|
-
end
|
79
|
-
|
80
|
-
# Indicates whether or not the relationship is defined by two inverse
|
81
|
-
# associations (e.g. a +has_many+ and a corresponding +belongs_to+
|
82
|
-
# association).
|
83
|
-
def mutual?
|
84
|
-
@forward_associations.any? and @reverse_associations.any?
|
85
|
-
end
|
86
|
-
|
87
|
-
# Indicates whether or not this relationship connects an entity with itself.
|
88
|
-
def recursive?
|
89
|
-
@source == @destination
|
90
|
-
end
|
91
|
-
|
92
|
-
# Indicates whether the destination cardinality class of this relationship
|
93
|
-
# is equal to one. This is +true+ for one-to-one relationships only.
|
94
|
-
def to_one?
|
95
|
-
cardinality.cardinality_class[1] == 1
|
96
|
-
end
|
97
|
-
|
98
|
-
# Indicates whether the destination cardinality class of this relationship
|
99
|
-
# is equal to infinity. This is +true+ for one-to-many or
|
100
|
-
# many-to-many relationships only.
|
101
|
-
def to_many?
|
102
|
-
cardinality.cardinality_class[1] != 1
|
103
|
-
end
|
104
|
-
|
105
|
-
# Indicates whether the source cardinality class of this relationship
|
106
|
-
# is equal to one. This is +true+ for one-to-one or
|
107
|
-
# one-to-many relationships only.
|
108
|
-
def one_to?
|
109
|
-
cardinality.cardinality_class[0] == 1
|
110
|
-
end
|
111
|
-
|
112
|
-
# Indicates whether the source cardinality class of this relationship
|
113
|
-
# is equal to infinity. This is +true+ for many-to-many relationships only.
|
114
|
-
def many_to?
|
115
|
-
cardinality.cardinality_class[0] != 1
|
116
|
-
end
|
117
|
-
|
118
|
-
# The strength of a relationship is equal to the number of associations
|
119
|
-
# that describe it.
|
120
|
-
def strength
|
121
|
-
associations.size
|
122
|
-
end
|
123
|
-
|
124
|
-
def inspect # @private :nodoc:
|
125
|
-
"#<#{self.class}:0x%.14x @source=#{source} @destination=#{destination}>" % (object_id << 1)
|
126
|
-
end
|
127
|
-
|
128
|
-
def <=>(other) # @private :nodoc:
|
129
|
-
(source.name <=> other.source.name).nonzero? or (destination.name <=> other.destination.name)
|
130
|
-
end
|
131
|
-
|
132
|
-
private
|
133
|
-
|
134
|
-
def associations_range(model, associations, absolute_max)
|
135
|
-
# The minimum of the range is the maximum value of each association
|
136
|
-
# minimum. If there is none, it is zero by definition. The reasoning is
|
137
|
-
# that from all associations, if only one has a required minimum, then
|
138
|
-
# this side of the relationship has a cardinality of at least one.
|
139
|
-
min = associations.map { |assoc| association_minimum(model, assoc) }.max || 0
|
140
|
-
|
141
|
-
# The maximum of the range is the maximum value of each association
|
142
|
-
# maximum. If there is none, it is equal to the absolute maximum. If
|
143
|
-
# only one association has a high cardinality on this side, the
|
144
|
-
# relationship itself has the same maximum cardinality.
|
145
|
-
max = associations.map { |assoc| association_maximum(model, assoc) }.max || absolute_max
|
146
|
-
|
147
|
-
min..max
|
148
|
-
end
|
149
|
-
|
150
|
-
def association_minimum(model, association)
|
151
|
-
minimum = association_validators(:presence, model, association).any? ||
|
152
|
-
foreign_key_required?(model, association) ? 1 : 0
|
153
|
-
length_validators = association_validators(:length, model, association)
|
154
|
-
length_validators.map { |v| v.options[:minimum] }.compact.max or minimum
|
155
|
-
end
|
156
|
-
|
157
|
-
def association_maximum(model, association)
|
158
|
-
maximum = association.collection? ? N : 1
|
159
|
-
length_validators = association_validators(:length, model, association)
|
160
|
-
length_validators.map { |v| v.options[:maximum] }.compact.min or maximum
|
161
|
-
end
|
162
|
-
|
163
|
-
def association_validators(kind, model, association)
|
164
|
-
model.validators_on(association.name).select { |v| v.kind == kind }
|
165
|
-
end
|
166
|
-
|
167
|
-
def any_habtm?(associations)
|
168
|
-
associations.any? { |association| association.macro == :has_and_belongs_to_many }
|
169
|
-
end
|
170
|
-
|
171
|
-
def foreign_key_required?(model, association)
|
172
|
-
if association.belongs_to?
|
173
|
-
key = model.arel_table.columns.find { |column| column.name == association.primary_key_name } and !key.null
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|