has_many_polymorphic 0.2.0 → 0.3.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.
@@ -1,175 +1,144 @@
|
|
1
|
-
module RussellEdge #:nodoc:
|
2
|
-
module HasManyPolymorphic #:nodoc:
|
3
|
-
|
4
|
-
def self.included(base)
|
5
|
-
base.extend(ClassMethods)
|
6
|
-
end
|
7
|
-
|
8
|
-
module ClassMethods
|
9
|
-
|
10
|
-
##
|
11
|
-
# HasManyPolymorphic
|
12
|
-
# This mixin adds a has many polymorphic relationship to a model and creates all the relationships needed
|
13
|
-
# by rails to handle it.
|
14
|
-
#
|
15
|
-
# Params
|
16
|
-
#
|
17
|
-
# Name - name of the relationship, there is a convention that whatever name you choose, the polymorphic
|
18
|
-
# table columns on your through table should match.
|
19
|
-
#
|
20
|
-
# Options
|
21
|
-
# - through - the model that handles the through relationship
|
22
|
-
# - models - models that should be included in this polymophic relationship
|
23
|
-
#
|
24
|
-
#
|
25
|
-
# One method is added for you to use
|
26
|
-
#
|
27
|
-
# - {name param}
|
28
|
-
# - the name of your relationship is used for the method name of this method. it will return
|
29
|
-
# an array of the models that are related via the has_many relationships
|
30
|
-
#
|
31
|
-
# There is an after_save call back that will save the relationships when they are added or removed
|
32
|
-
# If you want to remove a relationship the models need to be destroyed and this model reloaded.
|
33
|
-
#
|
34
|
-
# Example Usage
|
35
|
-
#
|
36
|
-
# class PreferenceType < ActiveRecord::Base
|
37
|
-
# has_morpheus :preferenced_records,
|
38
|
-
# :through => :valid_preference_types,
|
39
|
-
# :models => [:desktops, :organizers]
|
40
|
-
# end
|
41
|
-
#
|
42
|
-
# this gives you the following
|
43
|
-
#
|
44
|
-
# preferenceType = PreferenceType.first
|
45
|
-
# preferenceType.desktops
|
46
|
-
# preferenceType.organizers
|
47
|
-
#
|
48
|
-
# and
|
49
|
-
#
|
50
|
-
# preferenceType.preferenced_records
|
51
|
-
#
|
52
|
-
# which is a concatentated array of the models. You also get the following
|
53
|
-
#
|
54
|
-
# desktop = Desktop.first
|
55
|
-
# desktop.preference_types
|
56
|
-
#
|
57
|
-
# organizer = Organizer.first
|
58
|
-
# organizer.preference_types
|
59
|
-
##
|
60
|
-
|
61
|
-
def has_many_polymorphic(name, options = {})
|
62
|
-
target_class_name = self.name
|
63
|
-
instance_array_name = "#{name}_array".to_sym
|
64
|
-
|
65
|
-
#declare array to related models
|
66
|
-
attr_accessor instance_array_name
|
67
|
-
|
68
|
-
#create the has_many relationship
|
69
|
-
has_many options[:through], :dependent => :destroy
|
70
|
-
|
71
|
-
#create the has_many relationship for each model
|
72
|
-
options[:models].each do |model|
|
73
|
-
has_many model, :through => options[:through], :source => model.to_s.singularize,
|
74
|
-
:conditions => ["#{options[:through]}.#{name.to_s.singularize}_type = ?", model.to_s.classify], :dependent => :destroy
|
75
|
-
end
|
76
|
-
|
77
|
-
#modify the through class to add the belongs to relationships
|
78
|
-
options[:through].to_s.classify.constantize.class_exec do
|
79
|
-
options[:models].each do |model|
|
80
|
-
belongs_to model.to_s.singularize.to_sym, :class_name => model.to_s.classify, :foreign_key => "#{name.to_s.singularize}_id"
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
#I want to keep the << and push methods of array so this helps to keep them.
|
85
|
-
define_method name do
|
86
|
-
#used the declared instance variable array
|
87
|
-
records = self.send(instance_array_name.to_s)
|
88
|
-
records = records || []
|
89
|
-
options[:models].each do |model|
|
90
|
-
records = records | self.send(model.to_s)
|
91
|
-
end
|
92
|
-
|
93
|
-
#set it back to the instance variable
|
94
|
-
self.send("#{instance_array_name.to_s}=", records)
|
95
|
-
|
96
|
-
records
|
97
|
-
end
|
98
|
-
|
99
|
-
#before we save this model make sure you save all the relationships.
|
100
|
-
before_save do |record|
|
101
|
-
record.send(name).each do |reln_record|
|
102
|
-
conditions = "#{name.to_s.singularize}_id = #{reln_record.id} and #{name.to_s.singularize}_type = '#{reln_record.class.name}'"
|
103
|
-
exisiting_record = record.send("#{options[:through]}").find(:first,
|
104
|
-
:conditions => conditions)
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
values_hash
|
110
|
-
values_hash["#{name.
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
has_many
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
end
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
model.to_s.classify.constantize.class_eval do
|
150
|
-
#check if this is using STI if so use the type attribute else use the class name
|
151
|
-
def model_class_name
|
152
|
-
if attributes['type']
|
153
|
-
attributes['type']
|
154
|
-
else
|
155
|
-
self.class.to_s
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
module InstanceMethods
|
165
|
-
#clear array on reload
|
166
|
-
def reload(*args)
|
167
|
-
@records = []
|
168
|
-
|
169
|
-
super args
|
170
|
-
end
|
171
|
-
|
172
|
-
end
|
173
|
-
|
174
|
-
end
|
1
|
+
module RussellEdge #:nodoc:
|
2
|
+
module HasManyPolymorphic #:nodoc:
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
|
10
|
+
##
|
11
|
+
# HasManyPolymorphic
|
12
|
+
# This mixin adds a has many polymorphic relationship to a model and creates all the relationships needed
|
13
|
+
# by rails to handle it.
|
14
|
+
#
|
15
|
+
# Params
|
16
|
+
#
|
17
|
+
# Name - name of the relationship, there is a convention that whatever name you choose, the polymorphic
|
18
|
+
# table columns on your through table should match.
|
19
|
+
#
|
20
|
+
# Options
|
21
|
+
# - through - the model that handles the through relationship
|
22
|
+
# - models - models that should be included in this polymophic relationship
|
23
|
+
#
|
24
|
+
#
|
25
|
+
# One method is added for you to use
|
26
|
+
#
|
27
|
+
# - {name param}
|
28
|
+
# - the name of your relationship is used for the method name of this method. it will return
|
29
|
+
# an array of the models that are related via the has_many relationships
|
30
|
+
#
|
31
|
+
# There is an after_save call back that will save the relationships when they are added or removed
|
32
|
+
# If you want to remove a relationship the models need to be destroyed and this model reloaded.
|
33
|
+
#
|
34
|
+
# Example Usage
|
35
|
+
#
|
36
|
+
# class PreferenceType < ActiveRecord::Base
|
37
|
+
# has_morpheus :preferenced_records,
|
38
|
+
# :through => :valid_preference_types,
|
39
|
+
# :models => [:desktops, :organizers]
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# this gives you the following
|
43
|
+
#
|
44
|
+
# preferenceType = PreferenceType.first
|
45
|
+
# preferenceType.desktops
|
46
|
+
# preferenceType.organizers
|
47
|
+
#
|
48
|
+
# and
|
49
|
+
#
|
50
|
+
# preferenceType.preferenced_records
|
51
|
+
#
|
52
|
+
# which is a concatentated array of the models. You also get the following
|
53
|
+
#
|
54
|
+
# desktop = Desktop.first
|
55
|
+
# desktop.preference_types
|
56
|
+
#
|
57
|
+
# organizer = Organizer.first
|
58
|
+
# organizer.preference_types
|
59
|
+
##
|
60
|
+
|
61
|
+
def has_many_polymorphic(name, options = {})
|
62
|
+
target_class_name = self.name
|
63
|
+
instance_array_name = "#{name}_array".to_sym
|
64
|
+
|
65
|
+
#declare array to related models
|
66
|
+
attr_accessor instance_array_name
|
67
|
+
|
68
|
+
#create the has_many relationship
|
69
|
+
has_many options[:through], :dependent => :destroy
|
70
|
+
|
71
|
+
#create the has_many relationship for each model
|
72
|
+
options[:models].each do |model|
|
73
|
+
has_many model, :through => options[:through], :source => model.to_s.singularize,
|
74
|
+
:conditions => ["#{options[:through]}.#{name.to_s.singularize}_type = ?", model.to_s.classify], :dependent => :destroy
|
75
|
+
end
|
76
|
+
|
77
|
+
#modify the through class to add the belongs to relationships
|
78
|
+
options[:through].to_s.classify.constantize.class_exec do
|
79
|
+
options[:models].each do |model|
|
80
|
+
belongs_to model.to_s.singularize.to_sym, :class_name => model.to_s.classify, :foreign_key => "#{name.to_s.singularize}_id"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
#I want to keep the << and push methods of array so this helps to keep them.
|
85
|
+
define_method name do
|
86
|
+
#used the declared instance variable array
|
87
|
+
records = self.send(instance_array_name.to_s)
|
88
|
+
records = records || []
|
89
|
+
options[:models].each do |model|
|
90
|
+
records = records | self.send(model.to_s)
|
91
|
+
end
|
92
|
+
|
93
|
+
#set it back to the instance variable
|
94
|
+
self.send("#{instance_array_name.to_s}=", records)
|
95
|
+
|
96
|
+
records
|
97
|
+
end
|
98
|
+
|
99
|
+
#before we save this model make sure you save all the relationships.
|
100
|
+
before_save do |record|
|
101
|
+
record.send(name).each do |reln_record|
|
102
|
+
conditions = "#{name.to_s.singularize}_id = #{reln_record.id} and #{name.to_s.singularize}_type = '#{reln_record.class.name}'"
|
103
|
+
exisiting_record = record.send("#{options[:through]}").find(:first,
|
104
|
+
:conditions => conditions)
|
105
|
+
|
106
|
+
#handle STI get superclass class_name if not sub class of ActiveRecord::Base
|
107
|
+
class_name = (reln_record.superclass == ActiveRecord::Base) ? reln_record.class.name : reln_record.superclass.class.name
|
108
|
+
if exisiting_record.nil?
|
109
|
+
values_hash = {}
|
110
|
+
values_hash["#{record.class.name.underscore}_id"] = record.id
|
111
|
+
values_hash["#{name.to_s.singularize}_type"] = reln_record.class.name
|
112
|
+
values_hash["#{name.to_s.singularize}_id"] = reln_record.id
|
113
|
+
|
114
|
+
options[:through].to_s.classify.constantize.create(values_hash)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
#include instance methods into this model
|
120
|
+
include RussellEdge::HasManyPolymorphic::InstanceMethods
|
121
|
+
|
122
|
+
#add the relationship to the models.
|
123
|
+
options[:models].each do |model|
|
124
|
+
model.to_s.classify.constantize.class_exec do
|
125
|
+
has_many options[:through], :as => name.to_s.singularize
|
126
|
+
has_many target_class_name.tableize, :through => options[:through]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
module InstanceMethods
|
134
|
+
#clear array on reload
|
135
|
+
def reload(*args)
|
136
|
+
@records = []
|
137
|
+
|
138
|
+
super args
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
175
144
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: has_many_polymorphic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 3
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Russell Holmes
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-08-
|
18
|
+
date: 2011-08-24 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: activerecord
|