has_many_polymorphic 0.6.0 → 0.7.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/{MIT-LICENSE.txt → MIT-LICENSE} +19 -19
- data/README.md +90 -0
- data/Rakefile +28 -0
- data/lib/has_many_polymorphic.rb +4 -4
- data/lib/has_many_polymorphic/engine.rb +43 -43
- data/lib/has_many_polymorphic/has_many_polymorphic.rb +142 -142
- data/lib/has_many_polymorphic/version.rb +2 -2
- data/spec/db/database.yml +3 -0
- data/spec/db/schema.rb +22 -0
- data/spec/debug.log +48 -0
- data/spec/has_many_polymorphic_spec.rb +55 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/support/models.rb +20 -0
- metadata +51 -11
- data/README.rdoc +0 -54
@@ -1,20 +1,20 @@
|
|
1
|
-
Copyright (c) 2007-2011 Collective Idea
|
2
|
-
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
-
a copy of this software and associated documentation files (the
|
5
|
-
"Software"), to deal in the Software without restriction, including
|
6
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
-
permit persons to whom the Software is furnished to do so, subject to
|
9
|
-
the following conditions:
|
10
|
-
|
11
|
-
The above copyright notice and this permission notice shall be
|
12
|
-
included in all copies or substantial portions of the Software.
|
13
|
-
|
14
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
1
|
+
Copyright (c) 2007-2011 Collective Idea
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
20
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
#HasManyPolymorphic
|
2
|
+
|
3
|
+
This mixin adds a has many polymorphic relationship to a model and creates all the relationships needed by rails to handle it.
|
4
|
+
|
5
|
+
|
6
|
+
##Setup
|
7
|
+
|
8
|
+
You must define the models that you want to use inside an initializer using
|
9
|
+
|
10
|
+
RussellEdge::HasManyPolymorphic::Engine.add_models(%w(PreferenceType))
|
11
|
+
|
12
|
+
or
|
13
|
+
|
14
|
+
RussellEdge::HasManyPolymorphic::Engine.add_models("PreferenceType")
|
15
|
+
|
16
|
+
##Params
|
17
|
+
- Name
|
18
|
+
- name of the relationship, there is a convention that whatever name you choose, the polymorphic 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
|
+
##Added methods
|
26
|
+
|
27
|
+
- {name param}
|
28
|
+
- the name of your relationship is used for the method name of this method. it will return an array of the models that are related via the has_many relationships
|
29
|
+
|
30
|
+
There is an after_save call back that will save the relationships when they are added or removed. If you want to remove a relationship the models need to be destroyed and this model reloaded.
|
31
|
+
|
32
|
+
##Example Usage
|
33
|
+
|
34
|
+
###Schema
|
35
|
+
|
36
|
+
|
37
|
+
create_table :zoos, :force => true do |t|
|
38
|
+
t.string :name
|
39
|
+
end
|
40
|
+
|
41
|
+
create_table :monkeys, :force => true do |t|
|
42
|
+
t.string :name
|
43
|
+
end
|
44
|
+
|
45
|
+
create_table :bears, :force => true do |t|
|
46
|
+
t.string :name
|
47
|
+
end
|
48
|
+
|
49
|
+
create_table :birds, :force => true do |t|
|
50
|
+
t.string :name
|
51
|
+
end
|
52
|
+
|
53
|
+
create_table :zoo_animals, :force => true do |t|
|
54
|
+
t.integer :zoo_id
|
55
|
+
t.references :animal, :polymorphic => true
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
###Class
|
60
|
+
|
61
|
+
|
62
|
+
class Zoo < ActiveRecord::Base
|
63
|
+
has_many_polymorphic :animals,
|
64
|
+
:through => :zoo_animals,
|
65
|
+
:models => [:monkeys, :birds, :bears]
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
###What you get
|
70
|
+
|
71
|
+
zoo = Zoo.first
|
72
|
+
zoo.monkeys
|
73
|
+
zoo.birds
|
74
|
+
zoo.bears
|
75
|
+
|
76
|
+
and
|
77
|
+
|
78
|
+
zoo = Zoo.first
|
79
|
+
zoo.animals
|
80
|
+
|
81
|
+
which is a concatentated array of the models. You also get the following
|
82
|
+
|
83
|
+
monkey = Monkey.first
|
84
|
+
monkey.zoos
|
85
|
+
|
86
|
+
bird = Bird.first
|
87
|
+
bird.zoos
|
88
|
+
|
89
|
+
bear = Bear.first
|
90
|
+
bear.zoos
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'has_many_polymorphic/version'
|
6
|
+
|
7
|
+
require "rspec/core/rake_task"
|
8
|
+
RSpec::Core::RakeTask.new(:spec)
|
9
|
+
|
10
|
+
task :default => :spec
|
11
|
+
|
12
|
+
task :build do
|
13
|
+
system "gem build has_many_polymorphic.gemspec"
|
14
|
+
end
|
15
|
+
|
16
|
+
task :release => :build do
|
17
|
+
system "gem push has_many_polymorphic-#{HasManyPolymorphic::VERSION}.gem"
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'rdoc/task'
|
21
|
+
desc 'Generate documentation for the awesome_nested_set plugin.'
|
22
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
23
|
+
rdoc.rdoc_dir = 'rdoc'
|
24
|
+
rdoc.title = 'HasManyPolymorphic'
|
25
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
26
|
+
rdoc.rdoc_files.include('README.rdoc')
|
27
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
28
|
+
end
|
data/lib/has_many_polymorphic.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'has_many_polymorphic/has_many_polymorphic'
|
2
|
-
require 'has_many_polymorphic/engine'
|
3
|
-
|
4
|
-
|
1
|
+
require 'has_many_polymorphic/has_many_polymorphic'
|
2
|
+
require 'has_many_polymorphic/engine'
|
3
|
+
|
4
|
+
|
@@ -1,44 +1,44 @@
|
|
1
|
-
module RussellEdge
|
2
|
-
module HasManyPolymorphic
|
3
|
-
class Engine < Rails::Engine
|
4
|
-
isolate_namespace HasManyPolymorphic
|
5
|
-
DEFAULT_OPTIONS = {:models => %w()}
|
6
|
-
@@options = HashWithIndifferentAccess.new(DEFAULT_OPTIONS)
|
7
|
-
|
8
|
-
initializer "has_many_polymorphic.autoload_models", :after => :load_config_initializers do |app|
|
9
|
-
RussellEdge::HasManyPolymorphic::Engine.autoload_models
|
10
|
-
end
|
11
|
-
|
12
|
-
ActiveSupport.on_load(:active_record) do
|
13
|
-
include RussellEdge::HasManyPolymorphic
|
14
|
-
end
|
15
|
-
|
16
|
-
#set engine to scope
|
17
|
-
engine = self
|
18
|
-
config.to_prepare do
|
19
|
-
engine.autoload_models
|
20
|
-
end
|
21
|
-
|
22
|
-
class << self
|
23
|
-
def add_models(models)
|
24
|
-
if models.is_a? Array
|
25
|
-
@@options[:models] = @@options[:models] | models
|
26
|
-
else
|
27
|
-
@@options[:models] << models
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
# Dispatcher callback to load polymorphic relationships
|
32
|
-
def autoload_models
|
33
|
-
@@options[:models].each do |model|
|
34
|
-
#try to load model if it exists.
|
35
|
-
begin
|
36
|
-
model.constantize
|
37
|
-
rescue=>e
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
1
|
+
module RussellEdge
|
2
|
+
module HasManyPolymorphic
|
3
|
+
class Engine < Rails::Engine
|
4
|
+
isolate_namespace HasManyPolymorphic
|
5
|
+
DEFAULT_OPTIONS = {:models => %w()}
|
6
|
+
@@options = HashWithIndifferentAccess.new(DEFAULT_OPTIONS)
|
7
|
+
|
8
|
+
initializer "has_many_polymorphic.autoload_models", :after => :load_config_initializers do |app|
|
9
|
+
RussellEdge::HasManyPolymorphic::Engine.autoload_models
|
10
|
+
end
|
11
|
+
|
12
|
+
ActiveSupport.on_load(:active_record) do
|
13
|
+
include RussellEdge::HasManyPolymorphic
|
14
|
+
end
|
15
|
+
|
16
|
+
#set engine to scope
|
17
|
+
engine = self
|
18
|
+
config.to_prepare do
|
19
|
+
engine.autoload_models
|
20
|
+
end
|
21
|
+
|
22
|
+
class << self
|
23
|
+
def add_models(models)
|
24
|
+
if models.is_a? Array
|
25
|
+
@@options[:models] = @@options[:models] | models
|
26
|
+
else
|
27
|
+
@@options[:models] << models
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Dispatcher callback to load polymorphic relationships
|
32
|
+
def autoload_models
|
33
|
+
@@options[:models].each do |model|
|
34
|
+
#try to load model if it exists.
|
35
|
+
begin
|
36
|
+
model.constantize
|
37
|
+
rescue=>e
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
44
|
end
|
@@ -1,143 +1,143 @@
|
|
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
|
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
|
-
#handle STI get superclass class_name if not sub class of ActiveRecord::Base
|
103
|
-
klass_name = (reln_record.class.superclass == ActiveRecord::Base) ? reln_record.class.name : reln_record.class.superclass.name
|
104
|
-
conditions = "#{name.to_s.singularize}_id = #{reln_record.id} and #{name.to_s.singularize}_type = '#{klass_name}'"
|
105
|
-
exisiting_record = record.send("#{options[:through]}").find(:first,:conditions => conditions)
|
106
|
-
|
107
|
-
if exisiting_record.nil?
|
108
|
-
values_hash = {}
|
109
|
-
values_hash["#{record.class.name.underscore}_id"] = record.id
|
110
|
-
values_hash["#{name.to_s.singularize}_type"] = klass_name
|
111
|
-
values_hash["#{name.to_s.singularize}_id"] = reln_record.id
|
112
|
-
|
113
|
-
options[:through].to_s.classify.constantize.create(values_hash)
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
#include instance methods into this model
|
119
|
-
include RussellEdge::HasManyPolymorphic::InstanceMethods
|
120
|
-
|
121
|
-
#add the relationship to the models.
|
122
|
-
options[:models].each do |model|
|
123
|
-
model.to_s.classify.constantize.class_exec do
|
124
|
-
has_many options[:through], :as => name.to_s.singularize
|
125
|
-
has_many target_class_name.tableize, :through => options[:through]
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
module InstanceMethods
|
133
|
-
#clear array on reload
|
134
|
-
def reload(*args)
|
135
|
-
@records = []
|
136
|
-
|
137
|
-
super args
|
138
|
-
end
|
139
|
-
|
140
|
-
end
|
141
|
-
|
142
|
-
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
|
+
#handle STI get superclass class_name if not sub class of ActiveRecord::Base
|
103
|
+
klass_name = (reln_record.class.superclass == ActiveRecord::Base) ? reln_record.class.name : reln_record.class.superclass.name
|
104
|
+
conditions = "#{name.to_s.singularize}_id = #{reln_record.id} and #{name.to_s.singularize}_type = '#{klass_name}'"
|
105
|
+
exisiting_record = record.send("#{options[:through]}").find(:first,:conditions => conditions)
|
106
|
+
|
107
|
+
if exisiting_record.nil?
|
108
|
+
values_hash = {}
|
109
|
+
values_hash["#{record.class.name.underscore}_id"] = record.id
|
110
|
+
values_hash["#{name.to_s.singularize}_type"] = klass_name
|
111
|
+
values_hash["#{name.to_s.singularize}_id"] = reln_record.id
|
112
|
+
|
113
|
+
options[:through].to_s.classify.constantize.create(values_hash)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
#include instance methods into this model
|
119
|
+
include RussellEdge::HasManyPolymorphic::InstanceMethods
|
120
|
+
|
121
|
+
#add the relationship to the models.
|
122
|
+
options[:models].each do |model|
|
123
|
+
model.to_s.classify.constantize.class_exec do
|
124
|
+
has_many options[:through], :as => name.to_s.singularize
|
125
|
+
has_many target_class_name.tableize, :through => options[:through]
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
module InstanceMethods
|
133
|
+
#clear array on reload
|
134
|
+
def reload(*args)
|
135
|
+
@records = []
|
136
|
+
|
137
|
+
super args
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
143
|
end
|
@@ -1,3 +1,3 @@
|
|
1
|
-
module HasManyPolymorphic
|
2
|
-
VERSION = '0.
|
1
|
+
module HasManyPolymorphic
|
2
|
+
VERSION = '0.7.0' unless defined?(::HasManyPolymorphic::VERSION)
|
3
3
|
end
|
data/spec/db/schema.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
ActiveRecord::Schema.define(:version => 0) do
|
2
|
+
create_table :zoos, :force => true do |t|
|
3
|
+
t.string :name
|
4
|
+
end
|
5
|
+
|
6
|
+
create_table :monkeys, :force => true do |t|
|
7
|
+
t.string :name
|
8
|
+
end
|
9
|
+
|
10
|
+
create_table :bears, :force => true do |t|
|
11
|
+
t.string :name
|
12
|
+
end
|
13
|
+
|
14
|
+
create_table :birds, :force => true do |t|
|
15
|
+
t.string :name
|
16
|
+
end
|
17
|
+
|
18
|
+
create_table :zoo_animals, :force => true do |t|
|
19
|
+
t.integer :zoo_id
|
20
|
+
t.references :animal, :polymorphic => true
|
21
|
+
end
|
22
|
+
end
|
data/spec/debug.log
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# Logfile created on 2012-01-26 20:22:32 -0500 by logger.rb/31641
|
2
|
+
[1m[36m (10.0ms)[0m [1mselect sqlite_version(*)[0m
|
3
|
+
[1m[35m (110.0ms)[0m CREATE TABLE "zoos" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255))
|
4
|
+
[1m[36m (110.0ms)[0m [1mCREATE TABLE "monkies" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255)) [0m
|
5
|
+
[1m[35m (140.0ms)[0m CREATE TABLE "bears" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255))
|
6
|
+
[1m[36m (150.0ms)[0m [1mCREATE TABLE "birds" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255)) [0m
|
7
|
+
[1m[35m (150.0ms)[0m CREATE TABLE "zoo_animals" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "zoo_id" integer, "animal_id" integer, "animal_type" varchar(255))
|
8
|
+
[1m[36m (140.0ms)[0m [1mCREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL) [0m
|
9
|
+
[1m[35m (0.0ms)[0m PRAGMA index_list("schema_migrations")
|
10
|
+
[1m[36m (130.0ms)[0m [1mCREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")[0m
|
11
|
+
[1m[35m (0.0ms)[0m SELECT version FROM "schema_migrations"
|
12
|
+
[1m[36m (130.0ms)[0m [1mINSERT INTO "schema_migrations" (version) VALUES ('0')[0m
|
13
|
+
[1m[36m (20.0ms)[0m [1mselect sqlite_version(*)[0m
|
14
|
+
[1m[35m (100.0ms)[0m DROP TABLE "zoos"
|
15
|
+
[1m[36m (110.0ms)[0m [1mCREATE TABLE "zoos" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255)) [0m
|
16
|
+
[1m[35m (110.0ms)[0m DROP TABLE "monkies"
|
17
|
+
[1m[36m (110.0ms)[0m [1mCREATE TABLE "monkies" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255)) [0m
|
18
|
+
[1m[35m (130.0ms)[0m DROP TABLE "bears"
|
19
|
+
[1m[36m (160.0ms)[0m [1mCREATE TABLE "bears" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255)) [0m
|
20
|
+
[1m[35m (170.0ms)[0m DROP TABLE "birds"
|
21
|
+
[1m[36m (120.0ms)[0m [1mCREATE TABLE "birds" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255)) [0m
|
22
|
+
[1m[35m (120.0ms)[0m DROP TABLE "zoo_animals"
|
23
|
+
[1m[36m (130.0ms)[0m [1mCREATE TABLE "zoo_animals" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "zoo_id" integer, "animal_id" integer, "animal_type" varchar(255)) [0m
|
24
|
+
[1m[35m (0.0ms)[0m SELECT version FROM "schema_migrations"
|
25
|
+
[1m[36m (10.0ms)[0m [1mselect sqlite_version(*)[0m
|
26
|
+
[1m[35m (100.0ms)[0m DROP TABLE "zoos"
|
27
|
+
[1m[36m (110.0ms)[0m [1mCREATE TABLE "zoos" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255)) [0m
|
28
|
+
[1m[35m (120.0ms)[0m DROP TABLE "monkies"
|
29
|
+
[1m[36m (120.0ms)[0m [1mCREATE TABLE "monkies" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255)) [0m
|
30
|
+
[1m[35m (140.0ms)[0m DROP TABLE "bears"
|
31
|
+
[1m[36m (130.0ms)[0m [1mCREATE TABLE "bears" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255)) [0m
|
32
|
+
[1m[35m (120.0ms)[0m DROP TABLE "birds"
|
33
|
+
[1m[36m (130.0ms)[0m [1mCREATE TABLE "birds" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255)) [0m
|
34
|
+
[1m[35m (120.0ms)[0m DROP TABLE "zoo_animals"
|
35
|
+
[1m[36m (130.0ms)[0m [1mCREATE TABLE "zoo_animals" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "zoo_id" integer, "animal_id" integer, "animal_type" varchar(255)) [0m
|
36
|
+
[1m[35m (0.0ms)[0m SELECT version FROM "schema_migrations"
|
37
|
+
[1m[36m (10.0ms)[0m [1mselect sqlite_version(*)[0m
|
38
|
+
[1m[35m (90.0ms)[0m DROP TABLE "zoos"
|
39
|
+
[1m[36m (100.0ms)[0m [1mCREATE TABLE "zoos" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255)) [0m
|
40
|
+
[1m[35m (120.0ms)[0m DROP TABLE "monkies"
|
41
|
+
[1m[36m (110.0ms)[0m [1mCREATE TABLE "monkies" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255)) [0m
|
42
|
+
[1m[35m (120.0ms)[0m DROP TABLE "bears"
|
43
|
+
[1m[36m (120.0ms)[0m [1mCREATE TABLE "bears" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255)) [0m
|
44
|
+
[1m[35m (120.0ms)[0m DROP TABLE "birds"
|
45
|
+
[1m[36m (170.0ms)[0m [1mCREATE TABLE "birds" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "name" varchar(255)) [0m
|
46
|
+
[1m[35m (120.0ms)[0m DROP TABLE "zoo_animals"
|
47
|
+
[1m[36m (130.0ms)[0m [1mCREATE TABLE "zoo_animals" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "zoo_id" integer, "animal_id" integer, "animal_type" varchar(255)) [0m
|
48
|
+
[1m[35m (0.0ms)[0m SELECT version FROM "schema_migrations"
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "HasManyPolymorphic" do
|
4
|
+
before(:all) do
|
5
|
+
Zoo.create(:name => 'Zoo Lander')
|
6
|
+
Bear.create(:name => 'Smokey')
|
7
|
+
Bird.create(:name => 'Big Bird')
|
8
|
+
Monkey.create(:name => 'George')
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should have created the animals and zoo" do
|
12
|
+
Zoo.first.name.should eq 'Zoo Lander'
|
13
|
+
Monkey.find_by_name('George').name.should eq 'George'
|
14
|
+
Bird.find_by_name('Big Bird').name.should eq 'Big Bird'
|
15
|
+
Bear.find_by_name('Smokey').name.should eq 'Smokey'
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should allow you to add animals to a zoo" do
|
19
|
+
zoo = Zoo.first
|
20
|
+
zoo.animals.count.should eq 0
|
21
|
+
zoo.monkeys << Monkey.find_by_name('George')
|
22
|
+
zoo.birds << Bird.find_by_name('Big Bird')
|
23
|
+
zoo.bears << Bear.find_by_name('Smokey')
|
24
|
+
zoo.save
|
25
|
+
|
26
|
+
zoo.monkeys.count.should eq 1
|
27
|
+
zoo.monkeys.first.name.should eq 'George'
|
28
|
+
|
29
|
+
zoo.birds.count.should eq 1
|
30
|
+
zoo.birds.first.name.should eq 'Big Bird'
|
31
|
+
|
32
|
+
zoo.bears.count.should eq 1
|
33
|
+
zoo.bears.first.name.should eq 'Smokey'
|
34
|
+
|
35
|
+
zoo.animals.count.should eq 3
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should allow you to get the zoo from an animal" do
|
39
|
+
zoo = Zoo.first
|
40
|
+
|
41
|
+
zoo.monkeys << Monkey.find_by_name('George')
|
42
|
+
zoo.birds << Bird.find_by_name('Big Bird')
|
43
|
+
zoo.bears << Bear.find_by_name('Smokey')
|
44
|
+
zoo.save
|
45
|
+
|
46
|
+
monkey = Monkey.find_by_name('George')
|
47
|
+
monkey.zoos.first.id.should eq zoo.id
|
48
|
+
|
49
|
+
bird = Bird.find_by_name('Big Bird')
|
50
|
+
bird.zoos.first.id.should eq zoo.id
|
51
|
+
|
52
|
+
bear = Bear.find_by_name('Smokey')
|
53
|
+
bear.zoos.first.id.should eq zoo.id
|
54
|
+
end
|
55
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
2
|
+
plugin_test_dir = File.dirname(__FILE__)
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'bundler/setup'
|
6
|
+
require 'rspec'
|
7
|
+
require 'rails'
|
8
|
+
require 'active_support'
|
9
|
+
require 'active_model'
|
10
|
+
require 'active_record'
|
11
|
+
require 'action_controller'
|
12
|
+
require 'simplecov'
|
13
|
+
require 'rspec/rails'
|
14
|
+
|
15
|
+
SimpleCov.start
|
16
|
+
|
17
|
+
require 'has_many_polymorphic'
|
18
|
+
require 'support/models'
|
19
|
+
|
20
|
+
ActiveRecord::Base.configurations = YAML::load(ERB.new(IO.read(plugin_test_dir + "/db/database.yml")).result)
|
21
|
+
ActiveRecord::Base.establish_connection(ENV["DB"] || "spec")
|
22
|
+
ActiveRecord::Migration.verbose = false
|
23
|
+
load(File.join(plugin_test_dir, "db", "schema.rb"))
|
24
|
+
|
25
|
+
RussellEdge::HasManyPolymorphic::Engine.add_models("Zoo")
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Monkey < ActiveRecord::Base
|
2
|
+
end
|
3
|
+
|
4
|
+
class Bird < ActiveRecord::Base
|
5
|
+
end
|
6
|
+
|
7
|
+
class Bear < ActiveRecord::Base
|
8
|
+
end
|
9
|
+
|
10
|
+
class ZooAnimal < ActiveRecord::Base
|
11
|
+
belongs_to :zoo
|
12
|
+
belongs_to :animal, :polymorphic => true
|
13
|
+
end
|
14
|
+
|
15
|
+
class Zoo < ActiveRecord::Base
|
16
|
+
has_many_polymorphic :animals,
|
17
|
+
:through => :zoo_animals,
|
18
|
+
:models => [:monkeys, :birds, :bears]
|
19
|
+
end
|
20
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: has_many_polymorphic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,21 +9,54 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2012-01-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
16
|
-
requirement: &
|
15
|
+
name: rails
|
16
|
+
requirement: &27073632 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
-
- -
|
19
|
+
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
21
|
+
version: '3.1'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *27073632
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rspec-rails
|
27
|
+
requirement: &27058572 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2.7'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *27058572
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: sqlite3
|
38
|
+
requirement: &27059820 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.3.4
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *27059820
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: simplecov
|
49
|
+
requirement: &27064020 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.5'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *27064020
|
25
58
|
description: Simple replacement for has_many_polymorphs
|
26
|
-
email:
|
59
|
+
email: russonrails@gmail.com
|
27
60
|
executables: []
|
28
61
|
extensions: []
|
29
62
|
extra_rdoc_files: []
|
@@ -32,8 +65,15 @@ files:
|
|
32
65
|
- lib/has_many_polymorphic/has_many_polymorphic.rb
|
33
66
|
- lib/has_many_polymorphic/version.rb
|
34
67
|
- lib/has_many_polymorphic.rb
|
35
|
-
-
|
36
|
-
-
|
68
|
+
- spec/db/database.yml
|
69
|
+
- spec/db/schema.rb
|
70
|
+
- spec/debug.log
|
71
|
+
- spec/has_many_polymorphic_spec.rb
|
72
|
+
- spec/spec_helper.rb
|
73
|
+
- spec/support/models.rb
|
74
|
+
- MIT-LICENSE
|
75
|
+
- Rakefile
|
76
|
+
- README.md
|
37
77
|
homepage: https://github.com/russ1985/has_many_polymorphic
|
38
78
|
licenses: []
|
39
79
|
post_install_message:
|
@@ -54,7 +94,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
54
94
|
version: '0'
|
55
95
|
requirements: []
|
56
96
|
rubyforge_project:
|
57
|
-
rubygems_version: 1.8.
|
97
|
+
rubygems_version: 1.8.11
|
58
98
|
signing_key:
|
59
99
|
specification_version: 3
|
60
100
|
summary: Simple replacement for has_many_polymorphs
|
data/README.rdoc
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
= HasManyPolymorphic
|
2
|
-
|
3
|
-
This mixin adds a has many polymorphic relationship to a model and creates all the relationships needed by rails to handle it.
|
4
|
-
|
5
|
-
== Options
|
6
|
-
- Models
|
7
|
-
- the models you want to autoload so all the relationships are created on initialzation of Rails
|
8
|
-
|
9
|
-
== Setup
|
10
|
-
|
11
|
-
You must define the models that you want to use inside an initializer using
|
12
|
-
RussellEdge::HasManyPolymorphic.add_models(%w(PreferenceType)) or RussellEdge::HasManyPolymorphic.add_models("PreferenceType")
|
13
|
-
|
14
|
-
== Params
|
15
|
-
- Name
|
16
|
-
- name of the relationship, there is a convention that whatever name you choose, the polymorphic table columns on your through table should match.
|
17
|
-
|
18
|
-
- Options
|
19
|
-
- through - the model that handles the through relationship
|
20
|
-
- models - models that should be included in this polymophic relationship
|
21
|
-
|
22
|
-
|
23
|
-
== Added methods
|
24
|
-
|
25
|
-
- {name param}
|
26
|
-
- the name of your relationship is used for the method name of this method. it will return an array of the models that are related via the has_many relationships
|
27
|
-
|
28
|
-
There is an after_save call back that will save the relationships when they are added or removed. If you want to remove a relationship the models need to be destroyed and this model reloaded.
|
29
|
-
|
30
|
-
== Example Usage
|
31
|
-
|
32
|
-
class PreferenceType < ActiveRecord::Base
|
33
|
-
has_many_polymorphic :preferenced_records,
|
34
|
-
:through => :valid_preference_types,
|
35
|
-
:models => [:desktops, :organizers]
|
36
|
-
end
|
37
|
-
|
38
|
-
this gives you the following
|
39
|
-
|
40
|
-
preferenceType = PreferenceType.first
|
41
|
-
preferenceType.desktops
|
42
|
-
preferenceType.organizers
|
43
|
-
|
44
|
-
and
|
45
|
-
|
46
|
-
preferenceType.preferenced_records
|
47
|
-
|
48
|
-
which is a concatentated array of the models. You also get the following
|
49
|
-
|
50
|
-
desktop = Desktop.first
|
51
|
-
desktop.preference_types
|
52
|
-
|
53
|
-
organizer = Organizer.first
|
54
|
-
organizer.preference_types
|