has_many_polymorphs 2.2 → 2.9
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +0 -9
- data/README +6 -52
- data/TODO +1 -0
- data/generators/tagging/tagging_generator.rb +1 -14
- data/generators/tagging/templates/tag_test.rb +3 -8
- data/generators/tagging/templates/tagging.rb +2 -2
- data/generators/tagging/templates/tagging_extensions.rb +13 -106
- data/generators/tagging/templates/tagging_test.rb +14 -41
- data/generators/tagging/templates/taggings.yml +3 -5
- data/generators/tagging/templates/tags.yml +2 -2
- data/has_many_polymorphs.gemspec +36 -29
- data/lib/has_many_polymorphs.rb +5 -6
- data/lib/has_many_polymorphs/association.rb +8 -9
- data/lib/has_many_polymorphs/autoload.rb +16 -52
- data/lib/has_many_polymorphs/base.rb +3 -13
- data/lib/has_many_polymorphs/class_methods.rb +102 -181
- data/lib/has_many_polymorphs/debugging_tools.rb +0 -2
- data/lib/has_many_polymorphs/dependencies.rb +36 -0
- data/lib/has_many_polymorphs/rake_task_redefine_task.rb +1 -9
- data/lib/has_many_polymorphs/reflection.rb +6 -7
- data/lib/has_many_polymorphs/support_methods.rb +4 -10
- data/test/fixtures/{fish.yml → aquatic/fish.yml} +0 -0
- data/test/fixtures/{little_whale_pupils.yml → aquatic/little_whale_pupils.yml} +0 -0
- data/test/fixtures/{whales.yml → aquatic/whales.yml} +0 -0
- data/test/models/aquatic/fish.rb +1 -2
- data/test/models/aquatic/whale.rb +0 -2
- data/test/models/eaters_foodstuff.rb +3 -1
- data/test/models/petfood.rb +1 -2
- data/test/schema.rb +0 -15
- data/test/test_helper.rb +18 -39
- data/test/unit/{has_many_polymorphs_test.rb → polymorph_test.rb} +109 -181
- metadata +92 -265
- data.tar.gz.sig +0 -1
- data/Manifest +0 -173
- data/Rakefile +0 -28
- data/examples/hmph.rb +0 -69
- data/lib/has_many_polymorphs/configuration.rb +0 -19
- data/test/fixtures/people.yml +0 -7
- data/test/generator/tagging_generator_test.rb +0 -42
- data/test/integration/app/README +0 -182
- data/test/integration/app/Rakefile +0 -19
- data/test/integration/app/app/controllers/application.rb +0 -7
- data/test/integration/app/app/controllers/bones_controller.rb +0 -5
- data/test/integration/app/app/helpers/addresses_helper.rb +0 -2
- data/test/integration/app/app/helpers/application_helper.rb +0 -3
- data/test/integration/app/app/helpers/bones_helper.rb +0 -2
- data/test/integration/app/app/helpers/sellers_helper.rb +0 -28
- data/test/integration/app/app/helpers/states_helper.rb +0 -2
- data/test/integration/app/app/helpers/users_helper.rb +0 -2
- data/test/integration/app/app/models/bone.rb +0 -2
- data/test/integration/app/app/models/double_sti_parent.rb +0 -2
- data/test/integration/app/app/models/double_sti_parent_relationship.rb +0 -2
- data/test/integration/app/app/models/organic_substance.rb +0 -2
- data/test/integration/app/app/models/single_sti_parent.rb +0 -4
- data/test/integration/app/app/models/single_sti_parent_relationship.rb +0 -4
- data/test/integration/app/app/models/stick.rb +0 -2
- data/test/integration/app/app/models/stone.rb +0 -2
- data/test/integration/app/app/views/addresses/edit.html.erb +0 -12
- data/test/integration/app/app/views/addresses/index.html.erb +0 -18
- data/test/integration/app/app/views/addresses/new.html.erb +0 -11
- data/test/integration/app/app/views/addresses/show.html.erb +0 -3
- data/test/integration/app/app/views/bones/index.rhtml +0 -5
- data/test/integration/app/app/views/layouts/addresses.html.erb +0 -17
- data/test/integration/app/app/views/layouts/sellers.html.erb +0 -17
- data/test/integration/app/app/views/layouts/states.html.erb +0 -17
- data/test/integration/app/app/views/layouts/users.html.erb +0 -17
- data/test/integration/app/app/views/sellers/edit.html.erb +0 -12
- data/test/integration/app/app/views/sellers/index.html.erb +0 -20
- data/test/integration/app/app/views/sellers/new.html.erb +0 -11
- data/test/integration/app/app/views/sellers/show.html.erb +0 -3
- data/test/integration/app/app/views/states/edit.html.erb +0 -12
- data/test/integration/app/app/views/states/index.html.erb +0 -19
- data/test/integration/app/app/views/states/new.html.erb +0 -11
- data/test/integration/app/app/views/states/show.html.erb +0 -3
- data/test/integration/app/app/views/users/edit.html.erb +0 -12
- data/test/integration/app/app/views/users/index.html.erb +0 -22
- data/test/integration/app/app/views/users/new.html.erb +0 -11
- data/test/integration/app/app/views/users/show.html.erb +0 -3
- data/test/integration/app/config/boot.rb +0 -110
- data/test/integration/app/config/database.yml +0 -17
- data/test/integration/app/config/environment.rb +0 -19
- data/test/integration/app/config/environment.rb.canonical +0 -19
- data/test/integration/app/config/environments/development.rb +0 -9
- data/test/integration/app/config/environments/production.rb +0 -18
- data/test/integration/app/config/environments/test.rb +0 -19
- data/test/integration/app/config/locomotive.yml +0 -6
- data/test/integration/app/config/routes.rb +0 -33
- data/test/integration/app/config/ultrasphinx/default.base +0 -56
- data/test/integration/app/config/ultrasphinx/development.conf.canonical +0 -155
- data/test/integration/app/db/migrate/001_create_sticks.rb +0 -11
- data/test/integration/app/db/migrate/002_create_stones.rb +0 -11
- data/test/integration/app/db/migrate/003_create_organic_substances.rb +0 -11
- data/test/integration/app/db/migrate/004_create_bones.rb +0 -8
- data/test/integration/app/db/migrate/005_create_single_sti_parents.rb +0 -11
- data/test/integration/app/db/migrate/006_create_double_sti_parents.rb +0 -11
- data/test/integration/app/db/migrate/007_create_single_sti_parent_relationships.rb +0 -13
- data/test/integration/app/db/migrate/008_create_double_sti_parent_relationships.rb +0 -14
- data/test/integration/app/db/migrate/009_create_library_model.rb +0 -11
- data/test/integration/app/doc/README_FOR_APP +0 -2
- data/test/integration/app/generators/commenting_generator_test.rb +0 -83
- data/test/integration/app/lib/library_model.rb +0 -2
- data/test/integration/app/public/404.html +0 -30
- data/test/integration/app/public/500.html +0 -30
- data/test/integration/app/public/dispatch.cgi +0 -10
- data/test/integration/app/public/dispatch.fcgi +0 -24
- data/test/integration/app/public/dispatch.rb +0 -10
- data/test/integration/app/public/favicon.ico +0 -0
- data/test/integration/app/public/images/rails.png +0 -0
- data/test/integration/app/public/index.html +0 -277
- data/test/integration/app/public/javascripts/application.js +0 -2
- data/test/integration/app/public/javascripts/controls.js +0 -833
- data/test/integration/app/public/javascripts/dragdrop.js +0 -942
- data/test/integration/app/public/javascripts/effects.js +0 -1088
- data/test/integration/app/public/javascripts/prototype.js +0 -2515
- data/test/integration/app/public/robots.txt +0 -1
- data/test/integration/app/public/stylesheets/scaffold.css +0 -74
- data/test/integration/app/script/about +0 -3
- data/test/integration/app/script/breakpointer +0 -3
- data/test/integration/app/script/console +0 -3
- data/test/integration/app/script/destroy +0 -3
- data/test/integration/app/script/generate +0 -3
- data/test/integration/app/script/performance/benchmarker +0 -3
- data/test/integration/app/script/performance/profiler +0 -3
- data/test/integration/app/script/plugin +0 -3
- data/test/integration/app/script/process/inspector +0 -3
- data/test/integration/app/script/process/reaper +0 -3
- data/test/integration/app/script/process/spawner +0 -3
- data/test/integration/app/script/runner +0 -3
- data/test/integration/app/script/server +0 -3
- data/test/integration/app/test/fixtures/double_sti_parent_relationships.yml +0 -7
- data/test/integration/app/test/fixtures/double_sti_parents.yml +0 -7
- data/test/integration/app/test/fixtures/organic_substances.yml +0 -5
- data/test/integration/app/test/fixtures/single_sti_parent_relationships.yml +0 -7
- data/test/integration/app/test/fixtures/single_sti_parents.yml +0 -7
- data/test/integration/app/test/fixtures/sticks.yml +0 -7
- data/test/integration/app/test/fixtures/stones.yml +0 -7
- data/test/integration/app/test/functional/addresses_controller_test.rb +0 -57
- data/test/integration/app/test/functional/bones_controller_test.rb +0 -8
- data/test/integration/app/test/functional/sellers_controller_test.rb +0 -57
- data/test/integration/app/test/functional/states_controller_test.rb +0 -57
- data/test/integration/app/test/functional/users_controller_test.rb +0 -57
- data/test/integration/app/test/test_helper.rb +0 -8
- data/test/integration/app/test/unit/bone_test.rb +0 -8
- data/test/integration/app/test/unit/double_sti_parent_relationship_test.rb +0 -8
- data/test/integration/app/test/unit/double_sti_parent_test.rb +0 -8
- data/test/integration/app/test/unit/organic_substance_test.rb +0 -8
- data/test/integration/app/test/unit/single_sti_parent_relationship_test.rb +0 -8
- data/test/integration/app/test/unit/single_sti_parent_test.rb +0 -8
- data/test/integration/app/test/unit/stick_test.rb +0 -8
- data/test/integration/app/test/unit/stone_test.rb +0 -8
- data/test/integration/server_test.rb +0 -43
- data/test/models/parentship.rb +0 -4
- data/test/models/person.rb +0 -9
- data/test/patches/symlinked_plugins_1.2.6.diff +0 -46
- data/test/setup.rb +0 -14
- metadata.gz.sig +0 -0
data/has_many_polymorphs.gemspec
CHANGED
@@ -1,36 +1,43 @@
|
|
1
|
-
|
1
|
+
|
2
|
+
# Gem::Specification for Has_many_polymorphs-2.9
|
3
|
+
# Originally generated by Echoe
|
2
4
|
|
3
5
|
Gem::Specification.new do |s|
|
4
6
|
s.name = %q{has_many_polymorphs}
|
5
|
-
s.version = "2.
|
6
|
-
|
7
|
-
s.
|
8
|
-
s.authors = [""]
|
9
|
-
s.cert_chain = ["/Users/eweaver/p/configuration/gem_certificates/evan_weaver-original-public_cert.pem"]
|
10
|
-
s.date = %q{2009-11-18}
|
11
|
-
s.description = %q{An ActiveRecord plugin for self-referential and double-sided polymorphic associations.}
|
7
|
+
s.version = "2.9"
|
8
|
+
s.date = %q{2007-08-13}
|
9
|
+
s.summary = %q{An ActiveRecord plugin for self-referential and double-sided polymorphic associations.}
|
12
10
|
s.email = %q{}
|
13
|
-
s.
|
14
|
-
s.files = ["CHANGELOG", "examples/hmph.rb", "generators/tagging/tagging_generator.rb", "generators/tagging/templates/migration.rb", "generators/tagging/templates/tag.rb", "generators/tagging/templates/tag_test.rb", "generators/tagging/templates/tagging.rb", "generators/tagging/templates/tagging_extensions.rb", "generators/tagging/templates/tagging_test.rb", "generators/tagging/templates/taggings.yml", "generators/tagging/templates/tags.yml", "init.rb", "lib/has_many_polymorphs/association.rb", "lib/has_many_polymorphs/autoload.rb", "lib/has_many_polymorphs/base.rb", "lib/has_many_polymorphs/class_methods.rb", "lib/has_many_polymorphs/configuration.rb", "lib/has_many_polymorphs/debugging_tools.rb", "lib/has_many_polymorphs/rake_task_redefine_task.rb", "lib/has_many_polymorphs/reflection.rb", "lib/has_many_polymorphs/support_methods.rb", "lib/has_many_polymorphs.rb", "LICENSE", "Manifest", "Rakefile", "README", "test/fixtures/bow_wows.yml", "test/fixtures/cats.yml", "test/fixtures/eaters_foodstuffs.yml", "test/fixtures/fish.yml", "test/fixtures/frogs.yml", "test/fixtures/keep_your_enemies_close.yml", "test/fixtures/little_whale_pupils.yml", "test/fixtures/people.yml", "test/fixtures/petfoods.yml", "test/fixtures/whales.yml", "test/fixtures/wild_boars.yml", "test/generator/tagging_generator_test.rb", "test/integration/app/app/controllers/application.rb", "test/integration/app/app/controllers/bones_controller.rb", "test/integration/app/app/helpers/addresses_helper.rb", "test/integration/app/app/helpers/application_helper.rb", "test/integration/app/app/helpers/bones_helper.rb", "test/integration/app/app/helpers/sellers_helper.rb", "test/integration/app/app/helpers/states_helper.rb", "test/integration/app/app/helpers/users_helper.rb", "test/integration/app/app/models/bone.rb", "test/integration/app/app/models/double_sti_parent.rb", "test/integration/app/app/models/double_sti_parent_relationship.rb", "test/integration/app/app/models/organic_substance.rb", "test/integration/app/app/models/single_sti_parent.rb", "test/integration/app/app/models/single_sti_parent_relationship.rb", "test/integration/app/app/models/stick.rb", "test/integration/app/app/models/stone.rb", "test/integration/app/app/views/addresses/edit.html.erb", "test/integration/app/app/views/addresses/index.html.erb", "test/integration/app/app/views/addresses/new.html.erb", "test/integration/app/app/views/addresses/show.html.erb", "test/integration/app/app/views/bones/index.rhtml", "test/integration/app/app/views/layouts/addresses.html.erb", "test/integration/app/app/views/layouts/sellers.html.erb", "test/integration/app/app/views/layouts/states.html.erb", "test/integration/app/app/views/layouts/users.html.erb", "test/integration/app/app/views/sellers/edit.html.erb", "test/integration/app/app/views/sellers/index.html.erb", "test/integration/app/app/views/sellers/new.html.erb", "test/integration/app/app/views/sellers/show.html.erb", "test/integration/app/app/views/states/edit.html.erb", "test/integration/app/app/views/states/index.html.erb", "test/integration/app/app/views/states/new.html.erb", "test/integration/app/app/views/states/show.html.erb", "test/integration/app/app/views/users/edit.html.erb", "test/integration/app/app/views/users/index.html.erb", "test/integration/app/app/views/users/new.html.erb", "test/integration/app/app/views/users/show.html.erb", "test/integration/app/config/boot.rb", "test/integration/app/config/database.yml", "test/integration/app/config/environment.rb", "test/integration/app/config/environment.rb.canonical", "test/integration/app/config/environments/development.rb", "test/integration/app/config/environments/production.rb", "test/integration/app/config/environments/test.rb", "test/integration/app/config/locomotive.yml", "test/integration/app/config/routes.rb", "test/integration/app/config/ultrasphinx/default.base", "test/integration/app/config/ultrasphinx/development.conf.canonical", "test/integration/app/db/migrate/001_create_sticks.rb", "test/integration/app/db/migrate/002_create_stones.rb", "test/integration/app/db/migrate/003_create_organic_substances.rb", "test/integration/app/db/migrate/004_create_bones.rb", "test/integration/app/db/migrate/005_create_single_sti_parents.rb", "test/integration/app/db/migrate/006_create_double_sti_parents.rb", "test/integration/app/db/migrate/007_create_single_sti_parent_relationships.rb", "test/integration/app/db/migrate/008_create_double_sti_parent_relationships.rb", "test/integration/app/db/migrate/009_create_library_model.rb", "test/integration/app/doc/README_FOR_APP", "test/integration/app/generators/commenting_generator_test.rb", "test/integration/app/lib/library_model.rb", "test/integration/app/public/404.html", "test/integration/app/public/500.html", "test/integration/app/public/dispatch.cgi", "test/integration/app/public/dispatch.fcgi", "test/integration/app/public/dispatch.rb", "test/integration/app/public/favicon.ico", "test/integration/app/public/images/rails.png", "test/integration/app/public/index.html", "test/integration/app/public/javascripts/application.js", "test/integration/app/public/javascripts/controls.js", "test/integration/app/public/javascripts/dragdrop.js", "test/integration/app/public/javascripts/effects.js", "test/integration/app/public/javascripts/prototype.js", "test/integration/app/public/robots.txt", "test/integration/app/public/stylesheets/scaffold.css", "test/integration/app/Rakefile", "test/integration/app/README", "test/integration/app/script/about", "test/integration/app/script/breakpointer", "test/integration/app/script/console", "test/integration/app/script/destroy", "test/integration/app/script/generate", "test/integration/app/script/performance/benchmarker", "test/integration/app/script/performance/profiler", "test/integration/app/script/plugin", "test/integration/app/script/process/inspector", "test/integration/app/script/process/reaper", "test/integration/app/script/process/spawner", "test/integration/app/script/runner", "test/integration/app/script/server", "test/integration/app/test/fixtures/double_sti_parent_relationships.yml", "test/integration/app/test/fixtures/double_sti_parents.yml", "test/integration/app/test/fixtures/organic_substances.yml", "test/integration/app/test/fixtures/single_sti_parent_relationships.yml", "test/integration/app/test/fixtures/single_sti_parents.yml", "test/integration/app/test/fixtures/sticks.yml", "test/integration/app/test/fixtures/stones.yml", "test/integration/app/test/functional/addresses_controller_test.rb", "test/integration/app/test/functional/bones_controller_test.rb", "test/integration/app/test/functional/sellers_controller_test.rb", "test/integration/app/test/functional/states_controller_test.rb", "test/integration/app/test/functional/users_controller_test.rb", "test/integration/app/test/test_helper.rb", "test/integration/app/test/unit/bone_test.rb", "test/integration/app/test/unit/double_sti_parent_relationship_test.rb", "test/integration/app/test/unit/double_sti_parent_test.rb", "test/integration/app/test/unit/organic_substance_test.rb", "test/integration/app/test/unit/single_sti_parent_relationship_test.rb", "test/integration/app/test/unit/single_sti_parent_test.rb", "test/integration/app/test/unit/stick_test.rb", "test/integration/app/test/unit/stone_test.rb", "test/integration/server_test.rb", "test/models/aquatic/fish.rb", "test/models/aquatic/pupils_whale.rb", "test/models/aquatic/whale.rb", "test/models/beautiful_fight_relationship.rb", "test/models/canine.rb", "test/models/cat.rb", "test/models/dog.rb", "test/models/eaters_foodstuff.rb", "test/models/frog.rb", "test/models/kitten.rb", "test/models/parentship.rb", "test/models/person.rb", "test/models/petfood.rb", "test/models/tabby.rb", "test/models/wild_boar.rb", "test/modules/extension_module.rb", "test/modules/other_extension_module.rb", "test/patches/symlinked_plugins_1.2.6.diff", "test/schema.rb", "test/setup.rb", "test/test_helper.rb", "test/unit/has_many_polymorphs_test.rb", "TODO", "has_many_polymorphs.gemspec"]
|
15
|
-
s.homepage = %q{http://blog.evanweaver.com/files/doc/fauna/has_many_polymorphs/}
|
16
|
-
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Has_many_polymorphs", "--main", "README"]
|
17
|
-
s.require_paths = ["lib"]
|
11
|
+
s.homepage = %q{http://blog.evanweaver.com/pages/code#polymorphs}
|
18
12
|
s.rubyforge_project = %q{fauna}
|
19
|
-
s.
|
20
|
-
s.
|
21
|
-
s.
|
22
|
-
s.
|
13
|
+
s.description = %q{An ActiveRecord plugin for self-referential and double-sided polymorphic associations.}
|
14
|
+
s.has_rdoc = true
|
15
|
+
s.authors = [""]
|
16
|
+
s.files = ["test/unit/polymorph_test.rb", "test/test_helper.rb", "test/schema.rb", "test/modules/other_extension_module.rb", "test/modules/extension_module.rb", "test/models/wild_boar.rb", "test/models/tabby.rb", "test/models/petfood.rb", "test/models/kitten.rb", "test/models/frog.rb", "test/models/eaters_foodstuff.rb", "test/models/dog.rb", "test/models/cat.rb", "test/models/canine.rb", "test/models/beautiful_fight_relationship.rb", "test/models/aquatic/whale.rb", "test/models/aquatic/pupils_whale.rb", "test/models/aquatic/fish.rb", "test/fixtures/wild_boars.yml", "test/fixtures/petfoods.yml", "test/fixtures/keep_your_enemies_close.yml", "test/fixtures/frogs.yml", "test/fixtures/eaters_foodstuffs.yml", "test/fixtures/cats.yml", "test/fixtures/bow_wows.yml", "test/fixtures/aquatic/whales.yml", "test/fixtures/aquatic/little_whale_pupils.yml", "test/fixtures/aquatic/fish.yml", "lib/has_many_polymorphs.rb", "lib/has_many_polymorphs/support_methods.rb", "lib/has_many_polymorphs/reflection.rb", "lib/has_many_polymorphs/rake_task_redefine_task.rb", "lib/has_many_polymorphs/dependencies.rb", "lib/has_many_polymorphs/debugging_tools.rb", "lib/has_many_polymorphs/class_methods.rb", "lib/has_many_polymorphs/base.rb", "lib/has_many_polymorphs/autoload.rb", "lib/has_many_polymorphs/association.rb", "init.rb", "generators/tagging/templates/tags.yml", "generators/tagging/templates/taggings.yml", "generators/tagging/templates/tagging_test.rb", "generators/tagging/templates/tagging_extensions.rb", "generators/tagging/templates/tagging.rb", "generators/tagging/templates/tag_test.rb", "generators/tagging/templates/tag.rb", "generators/tagging/templates/migration.rb", "generators/tagging/tagging_generator.rb", "TODO", "README", "LICENSE", "CHANGELOG", "has_many_polymorphs.gemspec"]
|
17
|
+
s.test_files = ["test/test_helper.rb"]
|
18
|
+
s.add_dependency(%q<activerecord>, ["> 0.0.0"])
|
19
|
+
end
|
23
20
|
|
24
|
-
if s.respond_to? :specification_version then
|
25
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
26
|
-
s.specification_version = 3
|
27
21
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
22
|
+
# # Original Rakefile source (requires the Echoe gem):
|
23
|
+
#
|
24
|
+
#
|
25
|
+
# require 'rubygems'
|
26
|
+
# gem 'echoe', '>=2.2'
|
27
|
+
# require 'echoe'
|
28
|
+
# require 'lib/has_many_polymorphs/rake_task_redefine_task'
|
29
|
+
#
|
30
|
+
# Echoe.new("has_many_polymorphs") do |p|
|
31
|
+
# p.project = "fauna"
|
32
|
+
# p.summary = "An ActiveRecord plugin for self-referential and double-sided polymorphic associations."
|
33
|
+
# p.url = "http://blog.evanweaver.com/pages/code#polymorphs"
|
34
|
+
# p.docs_host = "blog.evanweaver.com:~/www/snax/public/files/doc/"
|
35
|
+
# p.dependencies = ["activerecord"]
|
36
|
+
# p.rdoc_pattern = /polymorphs\/association|polymorphs\/class_methods|polymorphs\/reflection|README|CHANGELOG|TODO|LICENSE|templates\/migration\.rb|templates\/tag\.rb|templates\/tagging\.rb|templates\/tagging_extensions\.rb/
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# desc 'Run the test suite.'
|
40
|
+
# Rake::Task.redefine_task("test") do
|
41
|
+
# puts "Warning! Tests must be run with the plugin installed in a functioning Rails\nenvironment."
|
42
|
+
# system "ruby -Ibin:lib:test test/unit/polymorph_test.rb #{ENV['METHOD'] ? "--name=#{ENV['METHOD']}" : ""}"
|
43
|
+
# end
|
data/lib/has_many_polymorphs.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
|
2
2
|
require 'active_record'
|
3
3
|
|
4
|
-
RAILS_DEFAULT_LOGGER = nil unless defined? RAILS_DEFAULT_LOGGER
|
5
|
-
|
6
4
|
require 'has_many_polymorphs/reflection'
|
7
5
|
require 'has_many_polymorphs/association'
|
8
6
|
require 'has_many_polymorphs/class_methods'
|
@@ -14,14 +12,15 @@ class ActiveRecord::Base
|
|
14
12
|
extend ActiveRecord::Associations::PolymorphicClassMethods
|
15
13
|
end
|
16
14
|
|
17
|
-
if ENV['HMP_DEBUG']
|
15
|
+
if ENV['HMP_DEBUG'] or (ENV['RAILS_ENV'] =~ /development|test/ and ENV['USER'] == 'eweaver')
|
16
|
+
_logger_warn "has_many_polymorphs: debug mode enabled"
|
18
17
|
require 'has_many_polymorphs/debugging_tools'
|
19
18
|
end
|
20
19
|
|
21
20
|
if defined? Rails and RAILS_ENV and RAILS_ROOT
|
22
|
-
_logger_warn "
|
23
|
-
require 'has_many_polymorphs/
|
21
|
+
_logger_warn "has_many_polymorphs: Rails environment detected"
|
22
|
+
require 'has_many_polymorphs/dependencies'
|
24
23
|
require 'has_many_polymorphs/autoload'
|
25
24
|
end
|
26
25
|
|
27
|
-
_logger_debug "loaded ok"
|
26
|
+
_logger_debug "has_many_polymorphs: loaded ok"
|
@@ -88,19 +88,18 @@ module ActiveRecord #:nodoc:
|
|
88
88
|
def construct_quoted_owner_attributes(*args) #:nodoc:
|
89
89
|
# no access to returning() here? why not?
|
90
90
|
type_key = @reflection.options[:foreign_type_key]
|
91
|
-
|
92
|
-
|
93
|
-
h
|
91
|
+
{@reflection.primary_key_name => @owner.id,
|
92
|
+
type_key=> (@owner.class.base_class.name if type_key)}
|
94
93
|
end
|
95
94
|
|
96
95
|
def construct_from #:nodoc:
|
97
96
|
# build the FROM part of the query, in this case, the polymorphic join table
|
98
|
-
@reflection.klass.
|
97
|
+
@reflection.klass.table_name
|
99
98
|
end
|
100
99
|
|
101
100
|
def construct_owner #:nodoc:
|
102
101
|
# the table name for the owner object's class
|
103
|
-
@owner.class.
|
102
|
+
@owner.class.table_name
|
104
103
|
end
|
105
104
|
|
106
105
|
def construct_owner_key #:nodoc:
|
@@ -115,10 +114,10 @@ module ActiveRecord #:nodoc:
|
|
115
114
|
|
116
115
|
def construct_joins(custom_joins = nil) #:nodoc:
|
117
116
|
# build the string of default joins
|
118
|
-
"JOIN #{construct_owner}
|
117
|
+
"JOIN #{construct_owner} polymorphic_parent ON #{construct_from}.#{@reflection.options[:foreign_key]} = polymorphic_parent.#{construct_owner_key} " +
|
119
118
|
@reflection.options[:from].map do |plural|
|
120
119
|
klass = plural._as_class
|
121
|
-
"LEFT JOIN #{klass.
|
120
|
+
"LEFT JOIN #{klass.table_name} ON #{construct_from}.#{@reflection.options[:polymorphic_key]} = #{klass.table_name}.#{klass.primary_key} AND #{construct_from}.#{@reflection.options[:polymorphic_type_key]} = #{@reflection.klass.quote_value(klass.base_class.name)}"
|
122
121
|
end.uniq.join(" ") + " #{custom_joins}"
|
123
122
|
end
|
124
123
|
|
@@ -154,7 +153,7 @@ module ActiveRecord #:nodoc:
|
|
154
153
|
raise PolymorphicMethodNotSupportedError, "You can't associate new records."
|
155
154
|
end
|
156
155
|
|
157
|
-
end
|
158
|
-
|
156
|
+
end
|
157
|
+
|
159
158
|
end
|
160
159
|
end
|
@@ -1,69 +1,33 @@
|
|
1
|
-
require 'initializer' unless defined? ::Rails::Initializer
|
2
|
-
require 'action_controller/dispatcher' unless defined? ::ActionController::Dispatcher
|
3
1
|
|
4
|
-
|
2
|
+
require 'initializer'
|
5
3
|
|
6
|
-
|
4
|
+
class Rails::Initializer
|
5
|
+
|
6
|
+
=begin rdoc
|
7
7
|
Searches for models that use <tt>has_many_polymorphs</tt> or <tt>acts_as_double_polymorphic_join</tt> and makes sure that they get loaded during app initialization. This ensures that helper methods are injected into the target classes.
|
8
8
|
|
9
|
-
|
10
|
-
Rails::Initializer.run do |config|
|
11
|
-
# your other configuration here
|
12
|
-
|
13
|
-
config.after_initialize do
|
14
|
-
config.has_many_polymorphs_options['requirements'] << 'lib/my_extension'
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
9
|
+
Overrides Rails::Initializer#after_initialize.
|
18
10
|
=end
|
19
11
|
|
20
|
-
|
21
|
-
|
22
|
-
:file_exclusions => ['svn', 'CVS', 'bzr'],
|
23
|
-
:methods => ['has_many_polymorphs', 'acts_as_double_polymorphic_join'],
|
24
|
-
:requirements => []}
|
25
|
-
|
26
|
-
mattr_accessor :options
|
27
|
-
@@options = HashWithIndifferentAccess.new(DEFAULT_OPTIONS)
|
28
|
-
|
29
|
-
# Dispatcher callback to load polymorphic relationships from the top down.
|
30
|
-
def self.autoload
|
31
|
-
|
32
|
-
_logger_debug "autoload hook invoked"
|
33
|
-
|
34
|
-
options[:requirements].each do |requirement|
|
35
|
-
_logger_warn "forcing requirement load of #{requirement}"
|
36
|
-
require requirement
|
37
|
-
end
|
12
|
+
def after_initialize_with_autoload
|
13
|
+
after_initialize_without_autoload
|
38
14
|
|
39
|
-
|
40
|
-
|
15
|
+
_logger_debug "has_many_polymorphs: autoload hook invoked"
|
16
|
+
Dir["#{RAILS_ROOT}/app/models/**/*.rb"].each do |filename|
|
17
|
+
next if filename =~ /svn|CVS|bzr/
|
41
18
|
open filename do |file|
|
42
|
-
if file.grep(
|
19
|
+
if file.grep(/has_many_polymorphs|acts_as_double_polymorphic_join/).any?
|
43
20
|
begin
|
44
|
-
model = File.basename(filename)[0..-4].
|
45
|
-
_logger_warn "preloading parent model #{model}"
|
21
|
+
model = File.basename(filename)[0..-4].classify
|
22
|
+
_logger_warn "has_many_polymorphs: preloading parent model #{model}"
|
46
23
|
model.constantize
|
47
24
|
rescue Object => e
|
48
|
-
_logger_warn "#{model}
|
25
|
+
_logger_warn "has_many_polymorphs: WARNING; possibly critical error preloading #{model}: #{e.inspect}"
|
49
26
|
end
|
50
27
|
end
|
51
28
|
end
|
52
29
|
end
|
53
30
|
end
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
class Rails::Initializer #:nodoc:
|
58
|
-
# Make sure it gets loaded in the console, tests, and migrations
|
59
|
-
def after_initialize_with_autoload
|
60
|
-
after_initialize_without_autoload
|
61
|
-
HasManyPolymorphs.autoload
|
62
|
-
end
|
63
|
-
alias_method_chain :after_initialize, :autoload
|
64
|
-
end
|
65
|
-
|
66
|
-
ActionController::Dispatcher.to_prepare(:has_many_polymorphs_autoload) do
|
67
|
-
# Make sure it gets loaded in the app
|
68
|
-
HasManyPolymorphs.autoload
|
31
|
+
|
32
|
+
alias_method_chain :after_initialize, :autoload
|
69
33
|
end
|
@@ -5,7 +5,7 @@ module ActiveRecord
|
|
5
5
|
class << self
|
6
6
|
|
7
7
|
# Interprets a polymorphic row from a unified SELECT, returning the appropriate ActiveRecord instance. Overrides ActiveRecord::Base.instantiate_without_callbacks.
|
8
|
-
def
|
8
|
+
def instantiate_without_callbacks_with_polymorphic_checks(record)
|
9
9
|
if record['polymorphic_parent_class']
|
10
10
|
reflection = record['polymorphic_parent_class'].constantize.reflect_on_association(record['polymorphic_association_id'].to_sym)
|
11
11
|
# _logger_debug "Instantiating a polymorphic row for #{record['polymorphic_parent_class']}.reflect_on_association(:#{record['polymorphic_association_id']})"
|
@@ -37,23 +37,13 @@ module ActiveRecord
|
|
37
37
|
# allocate and assign values
|
38
38
|
returning(klass.allocate) do |obj|
|
39
39
|
obj.instance_variable_set("@attributes", record)
|
40
|
-
obj.instance_variable_set("@attributes_cache", Hash.new)
|
41
|
-
|
42
|
-
if obj.respond_to_without_attributes?(:after_find)
|
43
|
-
obj.send(:callback, :after_find)
|
44
|
-
end
|
45
|
-
|
46
|
-
if obj.respond_to_without_attributes?(:after_initialize)
|
47
|
-
obj.send(:callback, :after_initialize)
|
48
|
-
end
|
49
|
-
|
50
40
|
end
|
51
41
|
else
|
52
|
-
|
42
|
+
instantiate_without_callbacks_without_polymorphic_checks(record)
|
53
43
|
end
|
54
44
|
end
|
55
45
|
|
56
|
-
alias_method_chain :
|
46
|
+
alias_method_chain :instantiate_without_callbacks, :polymorphic_checks
|
57
47
|
end
|
58
48
|
|
59
49
|
end
|
@@ -12,17 +12,14 @@ STI association targets must enumerated and named. For example, if Dog and Cat b
|
|
12
12
|
|
13
13
|
Namespaced models follow the Rails <tt>underscore</tt> convention. ZooAnimal::Lion becomes <tt>:'zoo_animal/lion'</tt>.
|
14
14
|
|
15
|
-
You do not need to set up any other associations other than for either the regular method or the double. The join associations and all individual and reverse associations are generated for you. However, a join
|
16
|
-
|
17
|
-
There is a tentative report that you can make the parent model be its own join model, but this is untested.
|
15
|
+
You do not need to set up any other associations other than for either the regular method or the double. The join associations and all individual and reverse associations are generated for you. However, a join class and table is required. There are tentative reports that it works without it if you make the parent class join to the targets <tt>:through</tt> itself, but this is untested.
|
18
16
|
|
19
17
|
=end
|
20
18
|
|
21
19
|
module PolymorphicClassMethods
|
22
20
|
|
23
|
-
|
24
|
-
:join_extend, :dependent, :rename_individual_collections
|
25
|
-
:namespace] #:nodoc:
|
21
|
+
RESERVED_KEYS = [:conditions, :order, :limit, :offset, :extend, :skip_duplicates,
|
22
|
+
:join_extend, :dependent, :rename_individual_collections] #:nodoc:
|
26
23
|
|
27
24
|
=begin rdoc
|
28
25
|
|
@@ -55,22 +52,41 @@ These options are passed through to targets on both sides of the association. If
|
|
55
52
|
<tt>:order</tt>:: A string for the SQL <tt>ORDER BY</tt> clause.
|
56
53
|
<tt>:limit</tt>:: An integer. Affects the polymorphic and individual associations.
|
57
54
|
<tt>:offset</tt>:: An integer. Only affects the polymorphic association.
|
58
|
-
|
59
|
-
|
55
|
+
|
60
56
|
=end
|
61
57
|
|
62
|
-
def acts_as_double_polymorphic_join options={}, &extension
|
58
|
+
def acts_as_double_polymorphic_join options={}, &extension
|
63
59
|
|
64
|
-
collections
|
60
|
+
collections = options._select {|k,v| v.is_a? Array and k.to_s !~ /(#{RESERVED_KEYS.map(&:to_s).join('|')})$/}
|
61
|
+
raise PolymorphicError, "Couldn't understand options in acts_as_double_polymorphic_join. Valid parameters are your two class collections, and then #{RESERVED_KEYS.inspect[1..-2]}, with optionally your collection names prepended and joined with an underscore." unless collections.size == 2
|
65
62
|
|
66
|
-
|
67
|
-
options[:extend] = (
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
end
|
72
|
-
|
73
|
-
|
63
|
+
options = options._select {|k,v| !collections[k]}
|
64
|
+
options[:extend] = (options[:extend] ? Array(options[:extend]) + [extension] : extension) if extension # inline the block
|
65
|
+
|
66
|
+
collection_option_keys = Hash[*collections.keys.map do |key|
|
67
|
+
[key, RESERVED_KEYS.map{|option| "#{key}_#{option}".to_sym}]
|
68
|
+
end._flatten_once]
|
69
|
+
|
70
|
+
collections.keys.each do |collection|
|
71
|
+
options.each do |key, value|
|
72
|
+
next if collection_option_keys.values.flatten.include? key
|
73
|
+
# shift the general options to the individual sides
|
74
|
+
collection_value = options[collection_key = "#{collection}_#{key}".to_sym]
|
75
|
+
case key
|
76
|
+
when :conditions
|
77
|
+
collection_value, value = sanitize_sql(collection_value), sanitize_sql(value)
|
78
|
+
options[collection_key] = (collection_value ? "(#{collection_value}) AND (#{value})" : value)
|
79
|
+
when :order
|
80
|
+
options[collection_key] = (collection_value ? "#{collection_value}, #{value}" : value)
|
81
|
+
when :extend, :join_extend
|
82
|
+
options[collection_key] = Array(collection_value) + Array(value)
|
83
|
+
when :limit, :offset, :dependent, :rename_individual_collections
|
84
|
+
options[collection_key] ||= value
|
85
|
+
else
|
86
|
+
raise PolymorphicError, "Unknown option key #{key.inspect}."
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
74
90
|
|
75
91
|
join_name = self.name.tableize.to_sym
|
76
92
|
collections.each do |association_id, children|
|
@@ -81,7 +97,7 @@ These options are passed through to targets on both sides of the association. If
|
|
81
97
|
rescue NoMethodError
|
82
98
|
raise PolymorphicError, "Couldn't find 'belongs_to' association for :#{parent_hash_key._singularize} in #{self.name}." unless parent_foreign_key
|
83
99
|
end
|
84
|
-
|
100
|
+
|
85
101
|
parents = collections[parent_hash_key]
|
86
102
|
conflicts = (children & parents) # set intersection
|
87
103
|
parents.each do |plural_parent_name|
|
@@ -89,31 +105,19 @@ These options are passed through to targets on both sides of the association. If
|
|
89
105
|
parent_class = plural_parent_name._as_class
|
90
106
|
singular_reverse_association_id = parent_hash_key._singularize
|
91
107
|
|
92
|
-
|
93
|
-
:is_double => true,
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
end.map do |key, value|
|
106
|
-
[key.to_s[association_id.to_s.length+1..-1].to_sym, value]
|
107
|
-
end._flatten_once] # rename side-specific options to general names
|
108
|
-
|
109
|
-
general_options.each do |key, value|
|
110
|
-
# avoid clobbering keys that appear in both option sets
|
111
|
-
if internal_options[key]
|
112
|
-
general_options[key] = Array(value) + Array(internal_options[key])
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
parent_class.send(:has_many_polymorphs, association_id, internal_options.merge(general_options))
|
108
|
+
parent_class.send(:has_many_polymorphs,
|
109
|
+
association_id, {:is_double => true,
|
110
|
+
:from => children,
|
111
|
+
:as => singular_reverse_association_id,
|
112
|
+
:through => join_name.to_sym,
|
113
|
+
:foreign_key => parent_foreign_key,
|
114
|
+
:foreign_type_key => parent_foreign_key.to_s.sub(/_id$/, '_type'),
|
115
|
+
:singular_reverse_association_id => singular_reverse_association_id,
|
116
|
+
:conflicts => conflicts}.merge(Hash[*options._select do |key, value|
|
117
|
+
collection_option_keys[association_id].include? key and !value.nil?
|
118
|
+
end.map do |key, value|
|
119
|
+
[key.to_s[association_id.to_s.length+1..-1].to_sym, value]
|
120
|
+
end._flatten_once])) # rename side-specific options to general names
|
117
121
|
|
118
122
|
if conflicts.include? plural_parent_name
|
119
123
|
# unify the alternate sides of the conflicting children
|
@@ -124,7 +128,7 @@ These options are passed through to targets on both sides of the association. If
|
|
124
128
|
self.send("#{association_id._singularize}_#{method_name}")).freeze
|
125
129
|
end
|
126
130
|
end
|
127
|
-
end
|
131
|
+
end
|
128
132
|
|
129
133
|
# unify the join model... join model is always renamed for doubles, unlike child associations
|
130
134
|
unless parent_class.instance_methods.include?(join_name)
|
@@ -142,54 +146,6 @@ These options are passed through to targets on both sides of the association. If
|
|
142
146
|
end
|
143
147
|
end
|
144
148
|
end
|
145
|
-
|
146
|
-
private
|
147
|
-
|
148
|
-
def extract_double_collections(options)
|
149
|
-
collections = options._select do |key, value|
|
150
|
-
value.is_a? Array and key.to_s !~ /(#{RESERVED_DOUBLES_KEYS.map(&:to_s).join('|')})$/
|
151
|
-
end
|
152
|
-
|
153
|
-
raise PolymorphicError, "Couldn't understand options in acts_as_double_polymorphic_join. Valid parameters are your two class collections, and then #{RESERVED_DOUBLES_KEYS.inspect[1..-2]}, with optionally your collection names prepended and joined with an underscore." unless collections.size == 2
|
154
|
-
|
155
|
-
options = options._select do |key, value|
|
156
|
-
!collections[key]
|
157
|
-
end
|
158
|
-
|
159
|
-
[collections, options]
|
160
|
-
end
|
161
|
-
|
162
|
-
def make_general_option_keys_specific!(options, collections)
|
163
|
-
collection_option_keys = Hash[*collections.keys.map do |key|
|
164
|
-
[key, RESERVED_DOUBLES_KEYS.map{|option| "#{key}_#{option}".to_sym}]
|
165
|
-
end._flatten_once]
|
166
|
-
|
167
|
-
collections.keys.each do |collection|
|
168
|
-
options.each do |key, value|
|
169
|
-
next if collection_option_keys.values.flatten.include? key
|
170
|
-
# shift the general options to the individual sides
|
171
|
-
collection_key = "#{collection}_#{key}".to_sym
|
172
|
-
collection_value = options[collection_key]
|
173
|
-
case key
|
174
|
-
when :conditions
|
175
|
-
collection_value, value = sanitize_sql(collection_value), sanitize_sql(value)
|
176
|
-
options[collection_key] = (collection_value ? "(#{collection_value}) AND (#{value})" : value)
|
177
|
-
when :order
|
178
|
-
options[collection_key] = (collection_value ? "#{collection_value}, #{value}" : value)
|
179
|
-
when :extend, :join_extend
|
180
|
-
options[collection_key] = Array(collection_value) + Array(value)
|
181
|
-
else
|
182
|
-
options[collection_key] ||= value
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
collection_option_keys
|
188
|
-
end
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
public
|
193
149
|
|
194
150
|
=begin rdoc
|
195
151
|
|
@@ -201,45 +157,36 @@ This method createds a single-sided polymorphic relationship.
|
|
201
157
|
|
202
158
|
The only required parameter, aside from the association name, is <tt>:from</tt>.
|
203
159
|
|
204
|
-
The method generates a number of associations aside from the polymorphic one. In this example Petfood also gets <tt>dogs</tt>, <tt>cats</tt>, and <tt>birds</tt>, and Dog, Cat, and Bird get <tt>petfoods</tt>. (The reverse association to the
|
160
|
+
The method generates a number of associations aside from the polymorphic one. In this example Petfood also gets <tt>dogs</tt>, <tt>cats</tt>, and <tt>birds</tt>, and Dog, Cat, and Bird get <tt>petfoods</tt>. (The reverse association to the parent is always plural.)
|
205
161
|
|
206
162
|
== Available options
|
207
163
|
|
208
|
-
<tt>:from</tt>:: An array of symbols representing the target
|
164
|
+
<tt>:from</tt>:: An array of symbols representing the target classes. Required.
|
209
165
|
<tt>:as</tt>:: A symbol for the parent's interface in the join--what the parent 'acts as'.
|
210
166
|
<tt>:through</tt>:: A symbol representing the class of the join model. Follows Rails defaults if not supplied (the parent and the association names, alphabetized, concatenated with an underscore, and singularized).
|
167
|
+
<tt>:foreign_key</tt>:: The column name for the parent's id in the join.
|
168
|
+
<tt>:foreign_type_key</tt>:: The column name for the parent's class in the join, if the parent itself is polymorphic. Rarely needed.
|
169
|
+
<tt>:polymorphic_key</tt>:: The column name for the child's id in the join.
|
170
|
+
<tt>:polymorphic_type_key</tt>:: The column name for the child's class in the join.
|
211
171
|
<tt>:dependent</tt>:: Accepts <tt>:destroy</tt>, <tt>:nullify</tt>, <tt>:delete_all</tt>. Controls how the join record gets treated on any associate delete (whether from the polymorph or from an individual collection); defaults to <tt>:destroy</tt>.
|
212
172
|
<tt>:skip_duplicates</tt>:: If <tt>true</tt>, will check to avoid pushing already associated records (but also triggering a database load). Defaults to <tt>true</tt>.
|
213
173
|
<tt>:rename_individual_collections</tt>:: If <tt>true</tt>, all individual collections are prepended with the polymorph name, and the children's parent collection is appended with "_of_#{association_name}"</tt>. For example, <tt>zoos</tt> becomes <tt>zoos_of_animals</tt>. This is to help avoid method name collisions in crowded classes.
|
214
174
|
<tt>:extend</tt>:: One or an array of mixed modules and procs, which are applied to the polymorphic association (usually to define custom methods).
|
215
175
|
<tt>:join_extend</tt>:: One or an array of mixed modules and procs, which are applied to the join association.
|
216
|
-
<tt>:parent_extend</tt>:: One or an array of mixed modules and procs, which are applied to the target
|
176
|
+
<tt>:parent_extend</tt>:: One or an array of mixed modules and procs, which are applied to the target classes' association to the parent.
|
217
177
|
<tt>:conditions</tt>:: An array or string of conditions for the SQL <tt>WHERE</tt> clause.
|
218
|
-
<tt>:parent_conditions</tt>:: An array or string of conditions which are applied to the target models' association to the parents.
|
219
178
|
<tt>:order</tt>:: A string for the SQL <tt>ORDER BY</tt> clause.
|
220
|
-
<tt>:parent_order</tt>:: A string for the SQL <tt>ORDER BY</tt> which is applied to the target models' association to the parents.
|
221
179
|
<tt>:group</tt>:: An array or string of conditions for the SQL <tt>GROUP BY</tt> clause. Affects the polymorphic and individual associations.
|
222
180
|
<tt>:limit</tt>:: An integer. Affects the polymorphic and individual associations.
|
223
181
|
<tt>:offset</tt>:: An integer. Only affects the polymorphic association.
|
224
|
-
<tt>:namespace</tt>:: A symbol. Prepended to all the models in the <tt>:from</tt> and <tt>:through</tt> keys. This is especially useful for Camping, which namespaces models by default.
|
225
182
|
<tt>:uniq</tt>:: If <tt>true</tt>, the records returned are passed through a pure-Ruby <tt>uniq</tt> before they are returned. Rarely needed.
|
226
|
-
<tt>:foreign_key</tt>:: The column name for the parent's id in the join.
|
227
|
-
<tt>:foreign_type_key</tt>:: The column name for the parent's class name in the join, if the parent itself is polymorphic. Rarely needed--if you're thinking about using this, you almost certainly want to use <tt>acts_as_double_polymorphic_join()</tt> instead.
|
228
|
-
<tt>:polymorphic_key</tt>:: The column name for the child's id in the join.
|
229
|
-
<tt>:polymorphic_type_key</tt>:: The column name for the child's class name in the join.
|
230
183
|
|
231
184
|
If you pass a block, it gets converted to a Proc and added to <tt>:extend</tt>.
|
232
185
|
|
233
|
-
== On condition nullification
|
234
|
-
|
235
|
-
When you request an individual association, non-applicable but fully-qualified fields in the polymorphic association's <tt>:conditions</tt>, <tt>:order</tt>, and <tt>:group</tt> options get changed to <tt>NULL</tt>. For example, if you set <tt>:conditions => "dogs.name != 'Spot'"</tt>, when you request <tt>.cats</tt>, the conditions string is changed to <tt>NULL != 'Spot'</tt>.
|
236
|
-
|
237
|
-
Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQL's 3-value logic. Instead, you need to use the <tt>:conditions</tt> string <tt>"dogs.name IS NULL OR dogs.name != 'Spot'"</tt> to get the behavior you probably expect for negative matches.
|
238
|
-
|
239
186
|
=end
|
240
187
|
|
241
188
|
def has_many_polymorphs (association_id, options = {}, &extension)
|
242
|
-
_logger_debug "associating #{self}.#{association_id}"
|
189
|
+
_logger_debug "has_many_polymorphs: associating #{self}.#{association_id}"
|
243
190
|
reflection = create_has_many_polymorphs_reflection(association_id, options, &extension)
|
244
191
|
# puts "Created reflection #{reflection.inspect}"
|
245
192
|
# configure_dependency_for_has_many(reflection)
|
@@ -272,8 +219,6 @@ Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQ
|
|
272
219
|
:select, # applies to the polymorphic relationship
|
273
220
|
:conditions, # applies to the polymorphic relationship, the children, and the join
|
274
221
|
# :include,
|
275
|
-
:parent_conditions,
|
276
|
-
:parent_order,
|
277
222
|
:order, # applies to the polymorphic relationship, the children, and the join
|
278
223
|
:group, # only applies to the polymorphic relationship and the children
|
279
224
|
:limit, # only applies to the polymorphic relationship and the children
|
@@ -283,7 +228,6 @@ Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQ
|
|
283
228
|
:parent_limit,
|
284
229
|
:parent_offset,
|
285
230
|
# :source,
|
286
|
-
:namespace,
|
287
231
|
:uniq, # XXX untested, only applies to the polymorphic relationship
|
288
232
|
# :finder_sql,
|
289
233
|
# :counter_sql,
|
@@ -298,13 +242,13 @@ Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQ
|
|
298
242
|
raise PolymorphicError, ":from option must be an array" unless options[:from].is_a? Array
|
299
243
|
options[:from].each{|plural| verify_pluralization_of(plural)}
|
300
244
|
|
301
|
-
options[:as] ||= self.name.demodulize.
|
245
|
+
options[:as] ||= self.name.demodulize.downcase.to_sym
|
302
246
|
options[:conflicts] = Array(options[:conflicts])
|
303
247
|
options[:foreign_key] ||= "#{options[:as]}_id"
|
304
248
|
|
305
249
|
options[:association_foreign_key] =
|
306
250
|
options[:polymorphic_key] ||= "#{association_id._singularize}_id"
|
307
|
-
options[:polymorphic_type_key] ||= "#{association_id._singularize}_type"
|
251
|
+
options[:polymorphic_type_key] ||= "#{association_id._singularize}_type"
|
308
252
|
|
309
253
|
if options.has_key? :ignore_duplicates
|
310
254
|
_logger_warn "DEPRECATION WARNING: please use :skip_duplicates instead of :ignore_duplicates"
|
@@ -314,20 +258,9 @@ Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQ
|
|
314
258
|
options[:dependent] = :destroy unless options.has_key? :dependent
|
315
259
|
options[:conditions] = sanitize_sql(options[:conditions])
|
316
260
|
|
317
|
-
|
318
|
-
|
319
|
-
options[:through] ||= build_join_table_symbol(
|
320
|
-
|
321
|
-
# set up namespaces if we have a namespace key
|
322
|
-
# XXX needs test coverage
|
323
|
-
if options[:namespace]
|
324
|
-
namespace = options[:namespace].to_s.chomp("/") + "/"
|
325
|
-
options[:from].map! do |child|
|
326
|
-
"#{namespace}#{child}".to_sym
|
327
|
-
end
|
328
|
-
options[:through] = "#{namespace}#{options[:through]}".to_sym
|
329
|
-
end
|
330
|
-
|
261
|
+
# options[:finder_sql] ||= "(options[:polymorphic_key]
|
262
|
+
|
263
|
+
options[:through] ||= build_join_table_symbol((options[:as]._pluralize or self.table_name), association_id)
|
331
264
|
options[:join_class_name] ||= options[:through]._classify
|
332
265
|
options[:table_aliases] ||= build_table_aliases([options[:through]] + options[:from])
|
333
266
|
options[:select] ||= build_select(association_id, options[:table_aliases])
|
@@ -340,7 +273,11 @@ Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQ
|
|
340
273
|
options[:parent_extend] = spiked_create_extension_module(association_id, Array(options[:parent_extend]), "Parent")
|
341
274
|
|
342
275
|
# create the reflection object
|
343
|
-
returning(create_reflection(:has_many_polymorphs, association_id, options, self)) do |reflection|
|
276
|
+
returning(create_reflection(:has_many_polymorphs, association_id, options, self)) do |reflection|
|
277
|
+
if defined? Dependencies and RAILS_ENV == "development"
|
278
|
+
inject_dependencies(association_id, reflection) if Dependencies.mechanism == :load
|
279
|
+
end
|
280
|
+
|
344
281
|
# set up the other related associations
|
345
282
|
create_join_association(association_id, reflection)
|
346
283
|
create_has_many_through_associations_for_parent_to_children(association_id, reflection)
|
@@ -357,17 +294,9 @@ Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQ
|
|
357
294
|
# for the targets
|
358
295
|
returning({}) do |aliases|
|
359
296
|
from.map(&:to_s).sort.map(&:to_sym).each_with_index do |plural, t_index|
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
raise PolymorphicError, "Could not find a valid class for #{plural.inspect} (tried #{plural.to_s._classify}). If it's namespaced, be sure to specify it as :\"module/#{plural}\" instead."
|
364
|
-
end
|
365
|
-
begin
|
366
|
-
plural._as_class.columns.map(&:name).each_with_index do |field, f_index|
|
367
|
-
aliases["#{table}.#{field}"] = "t#{t_index}_r#{f_index}"
|
368
|
-
end
|
369
|
-
rescue ActiveRecord::StatementInvalid => e
|
370
|
-
_logger_warn "Looks like your table doesn't exist for #{plural.to_s._classify}.\nError #{e}\nSkipping..."
|
297
|
+
table = plural._as_class.table_name
|
298
|
+
plural._as_class.columns.map(&:name).each_with_index do |field, f_index|
|
299
|
+
aliases["#{table}.#{field}"] = "t#{t_index}_r#{f_index}"
|
371
300
|
end
|
372
301
|
end
|
373
302
|
end
|
@@ -381,37 +310,43 @@ Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQ
|
|
381
310
|
"#{table} AS #{_alias}"
|
382
311
|
end.sort).join(", ")
|
383
312
|
end
|
384
|
-
|
313
|
+
|
314
|
+
# model caching
|
315
|
+
def inject_dependencies(association_id, reflection)
|
316
|
+
_logger_debug "has_many_polymorphs: injecting dependencies"
|
317
|
+
requirements = [self, reflection.klass].map{|klass| [klass, klass.base_class]}.flatten.uniq
|
318
|
+
(all_classes_for(association_id, reflection) - requirements).each do |target_klass|
|
319
|
+
Dependencies.inject_dependency(target_klass, *requirements)
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
385
323
|
# method sub-builders
|
386
324
|
|
387
325
|
def create_join_association(association_id, reflection)
|
388
326
|
|
389
|
-
options = {
|
390
|
-
:foreign_key => reflection.options[:foreign_key],
|
327
|
+
options = {:foreign_key => reflection.options[:foreign_key],
|
391
328
|
:dependent => reflection.options[:dependent],
|
392
329
|
:class_name => reflection.klass.name,
|
393
|
-
:extend => reflection.options[:join_extend]
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
}
|
330
|
+
:extend => reflection.options[:join_extend],
|
331
|
+
# :limit => reflection.options[:limit],
|
332
|
+
# :offset => reflection.options[:offset],
|
333
|
+
:order => devolve(association_id, reflection, reflection.options[:order], reflection.klass),
|
334
|
+
:conditions => devolve(association_id, reflection, reflection.options[:conditions], reflection.klass)
|
335
|
+
}
|
399
336
|
|
400
337
|
if reflection.options[:foreign_type_key]
|
401
|
-
type_check = "#{reflection.options[:
|
338
|
+
type_check = "#{reflection.options[:foreign_type_key]} = #{quote_value(self.base_class.name)}"
|
402
339
|
conjunction = options[:conditions] ? " AND " : nil
|
403
340
|
options[:conditions] = "#{options[:conditions]}#{conjunction}#{type_check}"
|
404
|
-
options[:as] = reflection.options[:as]
|
405
341
|
end
|
406
|
-
|
407
|
-
has_many(reflection.options[:through], options)
|
408
|
-
|
342
|
+
|
343
|
+
has_many(reflection.options[:through], options)
|
409
344
|
inject_before_save_into_join_table(association_id, reflection)
|
410
345
|
end
|
411
346
|
|
412
347
|
def inject_before_save_into_join_table(association_id, reflection)
|
413
348
|
sti_hook = "sti_class_rewrite"
|
414
|
-
rewrite_procedure = %[self.send(:#{
|
349
|
+
rewrite_procedure = %[self.send(:#{association_id._singularize}_type=, self.#{association_id._singularize}_type.constantize.base_class.name)]
|
415
350
|
|
416
351
|
# XXX should be abstracted?
|
417
352
|
reflection.klass.class_eval %[
|
@@ -452,34 +387,27 @@ Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQ
|
|
452
387
|
through = "#{reflection.options[:through]}#{'_as_child' if parent == self}".to_sym
|
453
388
|
has_many(through,
|
454
389
|
:as => association_id._singularize,
|
455
|
-
# :source => association_id._singularize,
|
456
|
-
# :source_type => reflection.options[:polymorphic_type_key],
|
457
390
|
:class_name => reflection.klass.name,
|
458
391
|
:dependent => reflection.options[:dependent],
|
459
392
|
:extend => reflection.options[:join_extend],
|
460
393
|
# :limit => reflection.options[:limit],
|
461
394
|
# :offset => reflection.options[:offset],
|
462
|
-
:order => devolve(association_id, reflection, reflection.options[:
|
463
|
-
:conditions => devolve(association_id, reflection, reflection.options[:
|
395
|
+
:order => devolve(association_id, reflection, reflection.options[:order], reflection.klass),
|
396
|
+
:conditions => devolve(association_id, reflection, reflection.options[:conditions], reflection.klass)
|
464
397
|
)
|
465
398
|
|
466
|
-
# the association to the
|
399
|
+
# the association to the collection parents
|
467
400
|
association = "#{reflection.options[:as]._pluralize}#{"_of_#{association_id}" if reflection.options[:rename_individual_collections]}".to_sym
|
468
401
|
has_many(association,
|
469
402
|
:through => through,
|
470
403
|
:class_name => parent.name,
|
471
404
|
:source => reflection.options[:as],
|
472
|
-
:foreign_key => reflection.options[:foreign_key],
|
405
|
+
:foreign_key => reflection.options[:foreign_key] ,
|
473
406
|
:extend => reflection.options[:parent_extend],
|
474
|
-
:conditions => reflection.options[:parent_conditions],
|
475
407
|
:order => reflection.options[:parent_order],
|
476
408
|
:offset => reflection.options[:parent_offset],
|
477
409
|
:limit => reflection.options[:parent_limit],
|
478
410
|
:group => reflection.options[:parent_group])
|
479
|
-
|
480
|
-
# debugger if association == :parents
|
481
|
-
#
|
482
|
-
# nil
|
483
411
|
|
484
412
|
end
|
485
413
|
end
|
@@ -524,8 +452,8 @@ Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQ
|
|
524
452
|
end
|
525
453
|
end
|
526
454
|
|
527
|
-
# some support methods
|
528
|
-
|
455
|
+
# some support methods
|
456
|
+
|
529
457
|
def child_pluralization_map(association_id, reflection)
|
530
458
|
Hash[*reflection.options[:from].map do |plural|
|
531
459
|
[plural, plural._singularize]
|
@@ -542,8 +470,8 @@ Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQ
|
|
542
470
|
s.to_s.gsub('/', '_').to_sym
|
543
471
|
end
|
544
472
|
|
545
|
-
def build_join_table_symbol(
|
546
|
-
[
|
473
|
+
def build_join_table_symbol(a, b)
|
474
|
+
[a.to_s, b.to_s].sort.join("_").to_sym
|
547
475
|
end
|
548
476
|
|
549
477
|
def all_classes_for(association_id, reflection)
|
@@ -552,25 +480,18 @@ Be aware, however, that <tt>NULL != 'Spot'</tt> returns <tt>false</tt> due to SQ
|
|
552
480
|
klasses.uniq
|
553
481
|
end
|
554
482
|
|
555
|
-
def devolve(association_id, reflection, string, klass
|
556
|
-
# XXX remove_inappropriate_clauses is not implemented; we'll wait until someone actually needs it
|
483
|
+
def devolve(association_id, reflection, string, klass)
|
557
484
|
return unless string
|
558
|
-
|
559
|
-
|
560
|
-
inappropriate_classes = (all_classes_for(association_id, reflection) - # the join class must always be preserved
|
561
|
-
[klass, klass.base_class, reflection.klass, reflection.klass.base_class])
|
562
|
-
inappropriate_classes.map do |klass|
|
485
|
+
(all_classes_for(association_id, reflection) - # the join class must always be preserved
|
486
|
+
[klass, klass.base_class, reflection.klass, reflection.klass.base_class]).map do |klass|
|
563
487
|
klass.columns.map do |column|
|
564
488
|
[klass.table_name, column.name]
|
565
489
|
end.map do |table, column|
|
566
490
|
["#{table}.#{column}", "`#{table}`.#{column}", "#{table}.`#{column}`", "`#{table}`.`#{column}`"]
|
567
491
|
end
|
568
492
|
end.flatten.sort_by(&:size).reverse.each do |quoted_reference|
|
569
|
-
# _logger_debug "devolved #{quoted_reference} to NULL"
|
570
|
-
# XXX clause removal would go here
|
571
493
|
string.gsub!(quoted_reference, "NULL")
|
572
494
|
end
|
573
|
-
# _logger_debug "altered to #{string}"
|
574
495
|
string
|
575
496
|
end
|
576
497
|
|