rails-erd 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|