polymorphic_integer_type 2.2.2 → 2.3.1

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.
Files changed (31) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +9 -9
  3. data/Rakefile +11 -0
  4. data/gemfiles/Gemfile.rails-4.2-stable +8 -0
  5. data/gemfiles/Gemfile.rails-4.2-stable.lock +68 -0
  6. data/gemfiles/Gemfile.rails-5.0-stable +8 -0
  7. data/gemfiles/Gemfile.rails-5.0-stable.lock +66 -0
  8. data/gemfiles/Gemfile.rails-5.1-stable +7 -0
  9. data/gemfiles/Gemfile.rails-5.1-stable.lock +66 -0
  10. data/gemfiles/Gemfile.rails-5.2-stable +7 -0
  11. data/gemfiles/Gemfile.rails-5.2-stable.lock +66 -0
  12. data/lib/polymorphic_integer_type.rb +12 -3
  13. data/lib/polymorphic_integer_type/{predicate_builder_extension.rb → activerecord_4/predicate_builder_extension.rb} +0 -0
  14. data/lib/polymorphic_integer_type/activerecord_5_0_0/association_query_handler_extension.rb +38 -0
  15. data/lib/polymorphic_integer_type/activerecord_5_0_0/polymorphic_array_value_extension.rb +34 -0
  16. data/lib/polymorphic_integer_type/belongs_to_polymorphic_association_extension.rb +12 -0
  17. data/lib/polymorphic_integer_type/extensions.rb +8 -25
  18. data/lib/polymorphic_integer_type/mapping.rb +1 -1
  19. data/lib/polymorphic_integer_type/module_generator.rb +34 -0
  20. data/lib/polymorphic_integer_type/version.rb +1 -1
  21. data/polymorphic_integer_type.gemspec +2 -2
  22. data/spec/polymorphic_integer_type_spec.rb +92 -18
  23. data/spec/spec_helper.rb +5 -1
  24. data/spec/support/configuration.rb +2 -2
  25. data/spec/support/migrations/6_create_plant_table.rb +17 -0
  26. data/spec/support/migrations/7_create_activity_table.rb +15 -0
  27. data/spec/support/namespaced_activity.rb +11 -0
  28. data/spec/support/namespaced_animal.rb +5 -1
  29. data/spec/support/namespaced_plant.rb +11 -0
  30. metadata +29 -10
  31. data/lib/polymorphic_integer_type/polymorphic_array_value_extension.rb +0 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 167cd58ce2ec474eea9268af532e07815e3c1a0c
4
- data.tar.gz: a523c263e4822806d3ce02543417658f4904c0a0
2
+ SHA256:
3
+ metadata.gz: 0d7804d64bb9623f7c1e99d9cc3e9d87660c4aa0377dcb990d0f36116e9d0f84
4
+ data.tar.gz: 4530a6917ae04b9e5b22823551a2c999909b32406d899aad950ac26373db333a
5
5
  SHA512:
6
- metadata.gz: e1913d6fea43ec6707438afbec0c60c8525e015e75062f8115afb7d4176143bb4efe8d79364dfd465d6551c8bb131815933fca85aa1df98813e62541ca8cca4d
7
- data.tar.gz: d4adcee63eeb967d4e4ecb17a53ec72cae5d23937c52a8e3030f4d27da9cf771b6a136583e9e0c2bf5a75ff31ab94895b2bcb2a7232ae140714a35961292242d
6
+ metadata.gz: 0017c3e990e834177af622495715ea839c720bd5d511faf9675ae74820e9bff2a2cf63c7d648b7098b135b009a88a7f5a8386ee359e412f22749c77980d18939
7
+ data.tar.gz: 156289387a5dd038b1c8380b18514e78f9f3c418c0fd0fff5deb844d8a94006ea742fd3cc47ed6948cf970f3e1dde106df0a60b781b388300ed969aa5f6bdb7c
data/README.md CHANGED
@@ -6,11 +6,11 @@ Rails' polymorphic associations are pretty useful. The example they give to set
6
6
  class Picture < ActiveRecord::Base
7
7
  belongs_to :imageable, polymorphic: true
8
8
  end
9
-
9
+
10
10
  class Employee < ActiveRecord::Base
11
11
  has_many :pictures, as: :imageable
12
12
  end
13
-
13
+
14
14
  class Product < ActiveRecord::Base
15
15
  has_many :pictures, as: :imageable
16
16
  end
@@ -31,7 +31,7 @@ class CreatePictures < ActiveRecord::Migration
31
31
  end
32
32
  ```
33
33
 
34
- The problem with this approach is that `imageable_type` is a string (and by default it is 255 characters). This is a little ridiculous. For comparison, if we had a state machine with X states, would we describe the states with strings `"State1", "State2", etc` or would we just enumerate the state column and make it an integer? This gem will allow us to use an integer for the `imageable_type` column.
34
+ The problem with this approach is that `imageable_type` is a string (and by default it is 255 characters). This is a little ridiculous. For comparison, if we had a state machine with X states, would we describe the states with strings `"State1", "State2", etc` or would we just enumerate the state column and make it an integer? This gem will allow us to use an integer for the `imageable_type` column.
35
35
 
36
36
  ## Installation
37
37
 
@@ -60,7 +60,7 @@ class Picture < ActiveRecord::Base
60
60
  belongs_to :imageable, polymorphic: {1 => "Employee", 2 => "Product"}
61
61
  end
62
62
  ```
63
-
63
+
64
64
  Next, include `PolymorphicIntegerType::Extensions` into any of the models that point back to the polymorphic integer type association (e.g., `Picture#imageable`) and add a [polymorphic association using `as:`](http://guides.rubyonrails.org/association_basics.html#polymorphic-associations).
65
65
 
66
66
  ```ruby
@@ -69,7 +69,7 @@ class Employee < ActiveRecord::Base
69
69
 
70
70
  has_many :pictures, as: :imageable
71
71
  end
72
-
72
+
73
73
  class Product < ActiveRecord::Base
74
74
  include PolymorphicIntegerType::Extensions
75
75
 
@@ -84,10 +84,10 @@ You can also store polymorphic type mappings separate from your models. This sho
84
84
  ```ruby
85
85
  PolymorphicIntegerType::Mapping.configuration do |config|
86
86
  config.add :imageable, {1 => "Employee", 2 => "Product" }
87
- end
87
+ end
88
88
  ```
89
89
 
90
- Note: The mapping here can start from whatever integer you wish, but I would advise not using 0. The reason being that if you had a new class, for instance `Avatar`, and also wanted to use this polymorphic association but forgot to include it in the mapping, it would effectively get `to_i` called on it and stored in the database. `"Avatar".to_i == 0`, so if your mapping included 0, this would create a weird bug.
90
+ Note: The mapping here can start from whatever integer you wish, but I would advise not using 0. The reason being that if you had a new class, for instance `Avatar`, and also wanted to use this polymorphic association but forgot to include it in the mapping, it would effectively get `to_i` called on it and stored in the database. `"Avatar".to_i == 0`, so if your mapping included 0, this would create a weird bug.
91
91
 
92
92
  ### Migrating an existing association
93
93
 
@@ -95,14 +95,14 @@ If you want to convert a polymorphic association that is already a string, you'l
95
95
 
96
96
  ```ruby
97
97
  class PictureToPolymorphicIntegerType < ActiveRecord::Migration
98
-
98
+
99
99
  def up
100
100
  change_table :pictures do |t|
101
101
  t.integer :new_imageable_type
102
102
  end
103
103
 
104
104
  execute <<-SQL
105
- UPDATE reminders
105
+ UPDATE picture
106
106
  SET new_imageable_type = CASE imageable_type
107
107
  WHEN 'Employee' THEN 1
108
108
  WHEN 'Product' THEN 2
data/Rakefile CHANGED
@@ -2,6 +2,17 @@ require "bundler/gem_tasks"
2
2
  require "yaml"
3
3
  require "active_record"
4
4
 
5
+ namespace :test do
6
+ task :all do
7
+ Dir.glob("./gemfiles/Gemfile*").each do |gemfile|
8
+ next if gemfile.end_with?(".lock")
9
+ puts "Running specs for #{Pathname.new(gemfile).basename}"
10
+ system("BUNDLE_GEMFILE=#{gemfile} bundle install > /dev/null && BUNDLE_GEMFILE=#{gemfile} bundle exec rspec")
11
+ puts ""
12
+ end
13
+ end
14
+ end
15
+
5
16
  namespace :db do
6
17
  database_config = YAML.load(File.open("./spec/support/database.yml"))
7
18
  admin_database_config = database_config.merge(database: "mysql")
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec path: ".."
6
+
7
+ gem "activerecord", github: "rails/rails", branch: "4-2-stable"
8
+ gem "sqlite3", "~> 1.3.6"
@@ -0,0 +1,68 @@
1
+ GIT
2
+ remote: git://github.com/rails/rails.git
3
+ revision: e9d6b85f3e834ceea2aeabe4cbaa96a7c73eb896
4
+ branch: 4-2-stable
5
+ specs:
6
+ activemodel (4.2.11.1)
7
+ activesupport (= 4.2.11.1)
8
+ builder (~> 3.1)
9
+ activerecord (4.2.11.1)
10
+ activemodel (= 4.2.11.1)
11
+ activesupport (= 4.2.11.1)
12
+ arel (~> 6.0)
13
+ activesupport (4.2.11.1)
14
+ i18n (~> 0.7)
15
+ minitest (~> 5.1)
16
+ thread_safe (~> 0.3, >= 0.3.4)
17
+ tzinfo (~> 1.1)
18
+
19
+ PATH
20
+ remote: ..
21
+ specs:
22
+ polymorphic_integer_type (2.2.4)
23
+ activerecord
24
+
25
+ GEM
26
+ remote: https://rubygems.org/
27
+ specs:
28
+ arel (6.0.4)
29
+ builder (3.2.4)
30
+ byebug (11.0.1)
31
+ concurrent-ruby (1.1.5)
32
+ diff-lcs (1.3)
33
+ i18n (0.9.5)
34
+ concurrent-ruby (~> 1.0)
35
+ minitest (5.13.0)
36
+ rake (13.0.1)
37
+ rspec (3.9.0)
38
+ rspec-core (~> 3.9.0)
39
+ rspec-expectations (~> 3.9.0)
40
+ rspec-mocks (~> 3.9.0)
41
+ rspec-core (3.9.0)
42
+ rspec-support (~> 3.9.0)
43
+ rspec-expectations (3.9.0)
44
+ diff-lcs (>= 1.2.0, < 2.0)
45
+ rspec-support (~> 3.9.0)
46
+ rspec-mocks (3.9.0)
47
+ diff-lcs (>= 1.2.0, < 2.0)
48
+ rspec-support (~> 3.9.0)
49
+ rspec-support (3.9.0)
50
+ sqlite3 (1.3.13)
51
+ thread_safe (0.3.6)
52
+ tzinfo (1.2.5)
53
+ thread_safe (~> 0.1)
54
+
55
+ PLATFORMS
56
+ ruby
57
+
58
+ DEPENDENCIES
59
+ activerecord!
60
+ bundler
61
+ byebug
62
+ polymorphic_integer_type!
63
+ rake
64
+ rspec
65
+ sqlite3 (~> 1.3.6)
66
+
67
+ BUNDLED WITH
68
+ 1.16.1
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec path: ".."
6
+
7
+ gem "activerecord", github: "rails/rails", branch: "5-0-stable"
8
+ gem "sqlite3", "~> 1.3.6"
@@ -0,0 +1,66 @@
1
+ GIT
2
+ remote: git://github.com/rails/rails.git
3
+ revision: ac6aa32f7cf66264ba87eabed7c042bb60bcf3a2
4
+ branch: 5-0-stable
5
+ specs:
6
+ activemodel (5.0.7.2)
7
+ activesupport (= 5.0.7.2)
8
+ activerecord (5.0.7.2)
9
+ activemodel (= 5.0.7.2)
10
+ activesupport (= 5.0.7.2)
11
+ arel (~> 7.0)
12
+ activesupport (5.0.7.2)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (>= 0.7, < 2)
15
+ minitest (~> 5.1)
16
+ tzinfo (~> 1.1)
17
+
18
+ PATH
19
+ remote: ..
20
+ specs:
21
+ polymorphic_integer_type (2.2.4)
22
+ activerecord
23
+
24
+ GEM
25
+ remote: https://rubygems.org/
26
+ specs:
27
+ arel (7.1.4)
28
+ byebug (11.0.1)
29
+ concurrent-ruby (1.1.5)
30
+ diff-lcs (1.3)
31
+ i18n (1.7.0)
32
+ concurrent-ruby (~> 1.0)
33
+ minitest (5.13.0)
34
+ rake (13.0.1)
35
+ rspec (3.9.0)
36
+ rspec-core (~> 3.9.0)
37
+ rspec-expectations (~> 3.9.0)
38
+ rspec-mocks (~> 3.9.0)
39
+ rspec-core (3.9.0)
40
+ rspec-support (~> 3.9.0)
41
+ rspec-expectations (3.9.0)
42
+ diff-lcs (>= 1.2.0, < 2.0)
43
+ rspec-support (~> 3.9.0)
44
+ rspec-mocks (3.9.0)
45
+ diff-lcs (>= 1.2.0, < 2.0)
46
+ rspec-support (~> 3.9.0)
47
+ rspec-support (3.9.0)
48
+ sqlite3 (1.3.13)
49
+ thread_safe (0.3.6)
50
+ tzinfo (1.2.5)
51
+ thread_safe (~> 0.1)
52
+
53
+ PLATFORMS
54
+ ruby
55
+
56
+ DEPENDENCIES
57
+ activerecord!
58
+ bundler
59
+ byebug
60
+ polymorphic_integer_type!
61
+ rake
62
+ rspec
63
+ sqlite3 (~> 1.3.6)
64
+
65
+ BUNDLED WITH
66
+ 1.16.1
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec path: ".."
6
+
7
+ gem "activerecord", github: "rails/rails", branch: "5-1-stable"
@@ -0,0 +1,66 @@
1
+ GIT
2
+ remote: git://github.com/rails/rails.git
3
+ revision: 663206d20aec374a28a24bb43bc7b1233042ed9b
4
+ branch: 5-1-stable
5
+ specs:
6
+ activemodel (5.1.7)
7
+ activesupport (= 5.1.7)
8
+ activerecord (5.1.7)
9
+ activemodel (= 5.1.7)
10
+ activesupport (= 5.1.7)
11
+ arel (~> 8.0)
12
+ activesupport (5.1.7)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (>= 0.7, < 2)
15
+ minitest (~> 5.1)
16
+ tzinfo (~> 1.1)
17
+
18
+ PATH
19
+ remote: ..
20
+ specs:
21
+ polymorphic_integer_type (2.2.4)
22
+ activerecord
23
+
24
+ GEM
25
+ remote: https://rubygems.org/
26
+ specs:
27
+ arel (8.0.0)
28
+ byebug (11.0.1)
29
+ concurrent-ruby (1.1.5)
30
+ diff-lcs (1.3)
31
+ i18n (1.7.0)
32
+ concurrent-ruby (~> 1.0)
33
+ minitest (5.13.0)
34
+ rake (13.0.1)
35
+ rspec (3.9.0)
36
+ rspec-core (~> 3.9.0)
37
+ rspec-expectations (~> 3.9.0)
38
+ rspec-mocks (~> 3.9.0)
39
+ rspec-core (3.9.0)
40
+ rspec-support (~> 3.9.0)
41
+ rspec-expectations (3.9.0)
42
+ diff-lcs (>= 1.2.0, < 2.0)
43
+ rspec-support (~> 3.9.0)
44
+ rspec-mocks (3.9.0)
45
+ diff-lcs (>= 1.2.0, < 2.0)
46
+ rspec-support (~> 3.9.0)
47
+ rspec-support (3.9.0)
48
+ sqlite3 (1.4.2)
49
+ thread_safe (0.3.6)
50
+ tzinfo (1.2.5)
51
+ thread_safe (~> 0.1)
52
+
53
+ PLATFORMS
54
+ ruby
55
+
56
+ DEPENDENCIES
57
+ activerecord!
58
+ bundler
59
+ byebug
60
+ polymorphic_integer_type!
61
+ rake
62
+ rspec
63
+ sqlite3
64
+
65
+ BUNDLED WITH
66
+ 1.16.1
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec path: ".."
6
+
7
+ gem "activerecord", github: "rails/rails", branch: "5-2-stable"
@@ -0,0 +1,66 @@
1
+ GIT
2
+ remote: git://github.com/rails/rails.git
3
+ revision: 892eab777c418135ce0646e91bc9ebb08a29ab9b
4
+ branch: 5-2-stable
5
+ specs:
6
+ activemodel (5.2.4.1)
7
+ activesupport (= 5.2.4.1)
8
+ activerecord (5.2.4.1)
9
+ activemodel (= 5.2.4.1)
10
+ activesupport (= 5.2.4.1)
11
+ arel (>= 9.0)
12
+ activesupport (5.2.4.1)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (>= 0.7, < 2)
15
+ minitest (~> 5.1)
16
+ tzinfo (~> 1.1)
17
+
18
+ PATH
19
+ remote: ..
20
+ specs:
21
+ polymorphic_integer_type (2.2.4)
22
+ activerecord
23
+
24
+ GEM
25
+ remote: https://rubygems.org/
26
+ specs:
27
+ arel (9.0.0)
28
+ byebug (11.0.1)
29
+ concurrent-ruby (1.1.5)
30
+ diff-lcs (1.3)
31
+ i18n (1.7.0)
32
+ concurrent-ruby (~> 1.0)
33
+ minitest (5.13.0)
34
+ rake (13.0.1)
35
+ rspec (3.9.0)
36
+ rspec-core (~> 3.9.0)
37
+ rspec-expectations (~> 3.9.0)
38
+ rspec-mocks (~> 3.9.0)
39
+ rspec-core (3.9.0)
40
+ rspec-support (~> 3.9.0)
41
+ rspec-expectations (3.9.0)
42
+ diff-lcs (>= 1.2.0, < 2.0)
43
+ rspec-support (~> 3.9.0)
44
+ rspec-mocks (3.9.0)
45
+ diff-lcs (>= 1.2.0, < 2.0)
46
+ rspec-support (~> 3.9.0)
47
+ rspec-support (3.9.0)
48
+ sqlite3 (1.4.2)
49
+ thread_safe (0.3.6)
50
+ tzinfo (1.2.5)
51
+ thread_safe (~> 0.1)
52
+
53
+ PLATFORMS
54
+ ruby
55
+
56
+ DEPENDENCIES
57
+ activerecord!
58
+ bundler
59
+ byebug
60
+ polymorphic_integer_type!
61
+ rake
62
+ rspec
63
+ sqlite3
64
+
65
+ BUNDLED WITH
66
+ 1.16.1
@@ -1,10 +1,19 @@
1
+ ACTIVE_RECORD_VERSION = Gem::Version.new(ActiveRecord::VERSION::STRING)
2
+
1
3
  require "polymorphic_integer_type/version"
2
4
  require "polymorphic_integer_type/extensions"
3
5
  require "polymorphic_integer_type/mapping"
4
- if Gem::Version.new(ActiveRecord::VERSION::STRING) < Gem::Version.new("5")
5
- require "polymorphic_integer_type/predicate_builder_extension"
6
+ require "polymorphic_integer_type/module_generator"
7
+ require "polymorphic_integer_type/belongs_to_polymorphic_association_extension"
8
+
9
+ if ACTIVE_RECORD_VERSION < Gem::Version.new("5")
10
+ require "polymorphic_integer_type/activerecord_4/predicate_builder_extension"
6
11
  else
7
- require "polymorphic_integer_type/polymorphic_array_value_extension"
12
+ require "polymorphic_integer_type/activerecord_5_0_0/polymorphic_array_value_extension"
13
+ end
14
+
15
+ if ACTIVE_RECORD_VERSION >= Gem::Version.new("5.0") && ACTIVE_RECORD_VERSION < Gem::Version.new("5.2.0")
16
+ require "polymorphic_integer_type/activerecord_5_0_0/association_query_handler_extension"
8
17
  end
9
18
 
10
19
  module PolymorphicIntegerType; end
@@ -0,0 +1,38 @@
1
+ module PolymorphicIntegerType
2
+ module AssociationQueryHandlerExtension
3
+ def call(attribute, value)
4
+ queries = {}
5
+ table = value.associated_table
6
+
7
+ if value.base_class
8
+ queries[table.association_foreign_type.to_s] = polymorphic_value_for(value)
9
+ end
10
+
11
+ queries[table.association_foreign_key.to_s] = value.ids
12
+ predicate_builder.build_from_hash(queries)
13
+ end
14
+
15
+ protected
16
+
17
+ def polymorphic_value_for(query_value)
18
+ table = query_value.associated_table
19
+ association = table.send(:association)
20
+ klass = association.active_record
21
+ name = association.name
22
+
23
+ if klass.respond_to?("#{name}_type_mapping")
24
+ type_mapping = klass.send("#{name}_type_mapping")
25
+
26
+ type_mapping.key(query_value.value.class.sti_name) ||
27
+ type_mapping.key(query_value.base_class.to_s) ||
28
+ type_mapping.key(query_value.base_class.sti_name)
29
+ else
30
+ query_value.base_class.name
31
+ end
32
+ end
33
+
34
+
35
+ end
36
+ end
37
+
38
+ ActiveRecord::PredicateBuilder::AssociationQueryHandler.prepend(PolymorphicIntegerType::AssociationQueryHandlerExtension)
@@ -0,0 +1,34 @@
1
+ module PolymorphicIntegerType
2
+ module PolymorphicArrayValueExtension
3
+
4
+ # original method:
5
+ # def type_to_ids_mapping
6
+ # default_hash = Hash.new { |hsh, key| hsh[key] = [] }
7
+ # result = values.each_with_object(default_hash) do |value, hash|
8
+ # hash[klass(value).polymorphic_name] << convert_to_id(value)
9
+ # end
10
+ # end
11
+
12
+ def type_to_ids_mapping
13
+ association = @associated_table.send(:association)
14
+ name = association.name
15
+ default_hash = Hash.new { |hsh, key| hsh[key] = [] }
16
+ values.each_with_object(default_hash) do |value, hash|
17
+ klass = respond_to?(:klass, true) ? klass(value) : value.class
18
+ if association.active_record.respond_to?("#{name}_type_mapping")
19
+ mapping = association.active_record.send("#{name}_type_mapping")
20
+ key ||= mapping.key(klass.polymorphic_name) if klass.respond_to?(:polymorphic_name)
21
+ key ||= mapping.key(klass.sti_name)
22
+ key ||= mapping.key(klass.base_class.to_s)
23
+ key ||= mapping.key(klass.base_class.sti_name)
24
+
25
+ hash[key] << convert_to_id(value)
26
+ else
27
+ hash[klass.polymorphic_name] << convert_to_id(value)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ ActiveRecord::PredicateBuilder::PolymorphicArrayValue.prepend(PolymorphicIntegerType::PolymorphicArrayValueExtension)
@@ -0,0 +1,12 @@
1
+ module ActiveRecord
2
+ module Associations
3
+ class BelongsToPolymorphicAssociation < BelongsToAssociation
4
+ private def replace_keys(record)
5
+ super
6
+ unless record.nil?
7
+ owner[reflection.foreign_type] = record.class.base_class
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -20,29 +20,11 @@ module PolymorphicIntegerType
20
20
  _polymorphic_foreign_types << foreign_type
21
21
 
22
22
  # Required way to dynamically define a class method on the model
23
- singleton_class.__send__(:define_method, "#{foreign_type}_mapping") do
23
+ define_singleton_method("#{foreign_type}_mapping") do
24
24
  mapping
25
25
  end
26
26
 
27
- define_method foreign_type do
28
- t = super()
29
- mapping[t]
30
- end
31
-
32
- define_method "#{foreign_type}=" do |klass|
33
- enum = mapping.key(klass.to_s)
34
- if klass.kind_of?(Class) && klass <= ActiveRecord::Base
35
- enum ||= mapping.key(klass.base_class.to_s)
36
- enum ||= mapping.key(klass.base_class.sti_name)
37
- end
38
- enum ||= klass if klass != NilClass
39
- super(enum)
40
- end
41
-
42
- define_method "#{name}=" do |record|
43
- super(record)
44
- send("#{foreign_type}=", record.class)
45
- end
27
+ ModuleGenerator.generate_and_include(self, foreign_type, name)
46
28
 
47
29
  validate do
48
30
  t = send(foreign_type)
@@ -63,14 +45,15 @@ module PolymorphicIntegerType
63
45
  if options[:as] && (polymorphic_type_mapping || integer_type)
64
46
  poly_type = options.delete(:as)
65
47
  polymorphic_type_mapping ||= PolymorphicIntegerType::Mapping[poly_type]
66
- if polymorphic_type_mapping == nil
48
+ if polymorphic_type_mapping.nil?
67
49
  raise "Polymorphic type mapping missing for #{poly_type.inspect}"
68
50
  end
69
51
 
70
- klass_mapping = (polymorphic_type_mapping || {}).key(sti_name)
52
+ klass_mapping = polymorphic_type_mapping.key(polymorphic_name) if respond_to?(:polymorphic_name)
53
+ klass_mapping ||= polymorphic_type_mapping.key(sti_name)
71
54
 
72
- if klass_mapping == nil
73
- raise "Class not found for #{sti_name.inspect} in polymorphic type mapping: #{polymorphic_type_mapping}"
55
+ if klass_mapping.nil?
56
+ raise "Class not found for #{inspect} in polymorphic type mapping: #{polymorphic_type_mapping}"
74
57
  end
75
58
 
76
59
  options[:foreign_key] ||= "#{poly_type}_id"
@@ -89,7 +72,7 @@ module PolymorphicIntegerType
89
72
  def retrieve_polymorphic_type_mapping(polymorphic_type:, class_name:)
90
73
  return if polymorphic_type.nil?
91
74
 
92
- belongs_to_class = class_name.safe_constantize
75
+ belongs_to_class = compute_type(class_name)
93
76
  method_name = "#{polymorphic_type}_type_mapping"
94
77
 
95
78
  if belongs_to_class && belongs_to_class.respond_to?(method_name)
@@ -15,6 +15,6 @@ module PolymorphicIntegerType
15
15
  @@mapping[as] || {}
16
16
  end
17
17
 
18
+ singleton_class.send(:alias_method, :[]=, :add)
18
19
  end
19
-
20
20
  end
@@ -0,0 +1,34 @@
1
+ module PolymorphicIntegerType
2
+ class ModuleGenerator
3
+ def self.generate_and_include(klass,foreign_type, name)
4
+ foreign_type_extension = Module.new do
5
+ define_method foreign_type do
6
+ t = super()
7
+ self.class.send("#{foreign_type}_mapping")[t]
8
+ end
9
+
10
+ define_method "#{foreign_type}=" do |klass|
11
+ mapping = self.class.send("#{foreign_type}_mapping")
12
+ enum = mapping.key(klass.to_s)
13
+ if klass.kind_of?(Class) && klass <= ActiveRecord::Base
14
+ enum ||= mapping.key(klass.polymorphic_name) if klass.respond_to?(:polymorphic_name)
15
+ enum ||= mapping.key(klass.sti_name)
16
+ enum ||= mapping.key(klass.base_class.to_s)
17
+ enum ||= mapping.key(klass.base_class.sti_name)
18
+ end
19
+ enum ||= klass if klass != NilClass
20
+ super(enum)
21
+ end
22
+
23
+ define_method "#{name}=" do |record|
24
+ super(record)
25
+ send("#{foreign_type}=", record.class)
26
+ association(name).loaded!
27
+ end
28
+ end
29
+
30
+ klass.include(foreign_type_extension)
31
+ end
32
+ end
33
+ end
34
+
@@ -1,3 +1,3 @@
1
1
  module PolymorphicIntegerType
2
- VERSION = "2.2.2"
2
+ VERSION = "2.3.1"
3
3
  end
@@ -18,10 +18,10 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency "activerecord"
21
+ spec.add_dependency "activerecord", "< 6"
22
22
  spec.add_development_dependency "bundler"
23
23
  spec.add_development_dependency "rake"
24
24
  spec.add_development_dependency "rspec"
25
25
  spec.add_development_dependency "sqlite3"
26
- spec.add_development_dependency "byebug"
26
+ spec.add_development_dependency "pry-byebug"
27
27
  end
@@ -14,6 +14,50 @@ describe PolymorphicIntegerType do
14
14
 
15
15
  let(:link) { Link.create(source: source, target: target) }
16
16
 
17
+
18
+ context "when creating associations" do
19
+ it "sets the source_type" do
20
+ link = dog.source_links.new
21
+ expect(link.source_type).to eq("Animal")
22
+ end
23
+
24
+ it "sets the target_type" do
25
+ link = kibble.target_links.new
26
+ expect(link.target_type).to eq("Food")
27
+ end
28
+
29
+ context "when models are namespaced" do
30
+ context "and mappings include namespaces" do
31
+ it "sets the source_type" do
32
+ allow(Link).to receive(:source_type_mapping).and_return({3 => "Namespaced::Plant"})
33
+ allow(Link).to receive(:source_type_mapping2).and_return({3 => "Namespaced::Plant"})
34
+
35
+ link = Namespaced::Plant.create(name: "Oak").source_links.new
36
+ expect(link.source_type).to eq("Namespaced::Plant")
37
+ end
38
+
39
+ it "sets the target_type" do
40
+ allow(Link).to receive(:target_type_mapping).and_return({3 => "Namespaced::Activity"})
41
+ link = Namespaced::Activity.create(name: "swaying").target_links.new
42
+ expect(link.target_type).to eq("Namespaced::Activity")
43
+ end
44
+ end
45
+
46
+ context "and mappings don't include namespaces" do
47
+ it "sets the source type" do
48
+ Link.source_type_mapping
49
+ link = Namespaced::Plant.create(name: "Oak").source_links.new
50
+ expect(link.source_type).to eq("Plant")
51
+ end
52
+
53
+ it "sets the target type" do
54
+ link = Namespaced::Activity.create(name:"swaying").target_links.new
55
+ expect(link.target_type).to eq("Activity")
56
+ end
57
+ end
58
+ end
59
+ end
60
+
17
61
  context "when the source is nil" do
18
62
  let(:source) { nil }
19
63
  let(:target) { nil }
@@ -24,22 +68,64 @@ describe PolymorphicIntegerType do
24
68
  end
25
69
  end
26
70
 
27
- context "when the source is a class that modifies the sti_name" do
71
+ context "when the source is a class that modifies the sti_name or polymorphic_name" do
72
+ context "and we leverage the polymorphic_name" do
73
+ before do
74
+ allow(PolymorphicIntegerType).to receive(:use_polymorphic_name).and_return(true)
75
+ end
76
+
77
+ it "properly sets the source_type to the modified class name" do
78
+ link = Link.new(source: Namespaced::Animal.new)
79
+ expect(link.source_type).to eql "Animal"
80
+ end
81
+
82
+ it "can read dirty attributes from an associated object" do
83
+ animal = Namespaced::Animal.create!(name: "Oldie")
84
+ animal.name = "Newton"
85
+ link = Link.create!(source: animal)
86
+
87
+ expect(link.source.name).to eq("Newton")
88
+ end
89
+ end
90
+
28
91
  it "properly sets the source_type to the modified class name" do
29
92
  link = Link.new(source: Namespaced::Animal.new)
30
93
  expect(link.source_type).to eql "Animal"
31
94
  end
95
+
96
+ it "can read dirty attributes from an associated object" do
97
+ animal = Namespaced::Animal.create!(name: "Oldie")
98
+ animal.name = "Newton"
99
+ link = Link.create!(source: animal)
100
+
101
+ expect(link.source.name).to eq("Newton")
102
+ end
32
103
  end
33
104
 
34
105
  context "when querying the associations" do
35
106
  let(:source) { cat }
36
107
  let(:target) { nil }
108
+
37
109
  it "properly finds the object with a where" do
38
110
  expect(Link.where(source: source, id: link.id).first).to eql link
39
111
  end
112
+
113
+ it "properly finds the object when passing an array of sources" do
114
+ expect(Link.where(source: [source])).to eq [link]
115
+ end
116
+
40
117
  it "properly finds the object with a find_by" do
41
118
  expect(Link.find_by(source: source, id: link.id)).to eql link
42
119
  end
120
+
121
+ context "when source and target are namespaced without modifying polymorphic_name" do
122
+ it "properly finds the object" do
123
+ plant = Namespaced::Plant.create(name: "Mighty", kind: "Oak", owner: owner)
124
+ activity = Namespaced::Activity.create(name: "swaying")
125
+ link = Link.create(source: plant, target: activity)
126
+ expect(Link.where(source: plant, id: link.id).first).to eql link
127
+ end
128
+ end
43
129
  end
44
130
 
45
131
  shared_examples "proper source" do
@@ -70,7 +156,6 @@ describe PolymorphicIntegerType do
70
156
  expect(source.source_links[0].source).to eql source
71
157
  end
72
158
  end
73
-
74
159
  end
75
160
  context "When a link is given polymorphic record" do
76
161
  let(:link) { Link.create(source: source) }
@@ -83,9 +168,7 @@ describe PolymorphicIntegerType do
83
168
 
84
169
  include_examples "proper source"
85
170
  include_examples "proper target"
86
-
87
171
  end
88
-
89
172
  end
90
173
 
91
174
  context "When a link is given polymorphic id and type" do
@@ -98,12 +181,10 @@ describe PolymorphicIntegerType do
98
181
  before { link.update_attributes(target_id: target.id, target_type: target.class.to_s) }
99
182
  include_examples "proper source"
100
183
  include_examples "proper target"
101
-
102
184
  end
103
-
104
185
  end
105
186
 
106
- context "When using a relation to the links with eagar loading" do
187
+ context "When using a relation to the links with eager loading" do
107
188
  let!(:links){
108
189
  [Link.create(source: source, target: kibble),
109
190
  Link.create(source: source, target: water)]
@@ -113,12 +194,10 @@ describe PolymorphicIntegerType do
113
194
  it "should be able to return the links and the targets" do
114
195
  expect(cat.source_links).to match_array links
115
196
  expect(cat.source_links.includes(:target).collect(&:target)).to match_array [water, kibble]
116
-
117
197
  end
118
-
119
198
  end
120
199
 
121
- context "When using a through relation to the links with eagar loading" do
200
+ context "When using a through relation to the links with eager loading" do
122
201
  let!(:links){
123
202
  [Link.create(source: source, target: kibble),
124
203
  Link.create(source: source, target: water)]
@@ -128,12 +207,10 @@ describe PolymorphicIntegerType do
128
207
  it "should be able to return the links and the targets" do
129
208
  expect(owner.pet_source_links).to match_array links
130
209
  expect(owner.pet_source_links.includes(:target).collect(&:target)).to match_array [water, kibble]
131
-
132
210
  end
133
-
134
211
  end
135
212
 
136
- context "When eagar loading the polymorphic association" do
213
+ context "When eager loading the polymorphic association" do
137
214
  let(:link) { Link.create(source_id: source.id, source_type: source.class.to_s) }
138
215
  let(:source) { cat }
139
216
 
@@ -145,15 +222,12 @@ describe PolymorphicIntegerType do
145
222
  expect(links.first.source).to eql cat
146
223
  expect(links.last.source).to eql dog
147
224
  end
148
-
149
225
  end
150
226
 
151
227
  it "should be able to preload the association" do
152
228
  l = Link.includes(:source).where(id: link.id).first
153
229
  expect(l.source).to eql cat
154
230
  end
155
-
156
-
157
231
  end
158
232
 
159
233
  context "when the association is an STI table" do
@@ -205,7 +279,7 @@ describe PolymorphicIntegerType do
205
279
  include_examples "proper target"
206
280
 
207
281
  it "creates foreign_type mapping method" do
208
- expect(Link.source_type_mapping).to eq({1 => "Person", 2 => "Animal"})
282
+ expect(Link.source_type_mapping).to eq({1 => "Person", 2 => "Animal", 3 => "Plant"})
209
283
  expect(InlineLink.source_type_mapping).to eq({10 => "Person", 11 => "InlineAnimal"})
210
284
  end
211
285
 
@@ -246,7 +320,7 @@ describe PolymorphicIntegerType do
246
320
 
247
321
  self.table_name = "drinks"
248
322
 
249
- has_many :inline_links2, as: :target
323
+ has_many :inline_link2s, as: :target
250
324
  end
251
325
 
252
326
  let!(:animal) { InlineAnimal2.create!(name: "Lucy") }
@@ -5,16 +5,20 @@ require 'support/configuration'
5
5
  require 'support/link'
6
6
  require 'support/animal'
7
7
  require 'support/namespaced_animal'
8
+ require 'support/namespaced_plant'
8
9
  require 'support/dog'
9
10
  require 'support/person'
10
11
  require 'support/food'
11
12
  require 'support/drink'
13
+ require 'support/namespaced_activity'
14
+ require 'byebug'
15
+ require 'pry'
12
16
 
13
17
  RSpec.configure do |config|
14
18
  config.before(:suite) do
15
19
  database_config = YAML.load(File.open("#{File.dirname(__FILE__)}/support/database.yml"))
16
20
  ActiveRecord::Base.establish_connection(database_config)
17
- if Gem::Version.new(ActiveRecord::VERSION::STRING) >= Gem::Version.new("5")
21
+ if Gem::Version.new(ActiveRecord::VERSION::STRING) >= Gem::Version.new("5.2.0")
18
22
  ActiveRecord::MigrationContext.new("#{File.dirname(__FILE__)}/support/migrations").migrate
19
23
  end
20
24
  end
@@ -1,4 +1,4 @@
1
1
  PolymorphicIntegerType::Mapping.configuration do |config|
2
- config.add :source, {1 => "Person", 2 => "Animal"}
3
- config.add :target, {1 => "Food", 2 => "Drink"}
2
+ config.add :source, {1 => "Person", 2 => "Animal", 3 => "Plant"}
3
+ config.add :target, {1 => "Food", 2 => "Drink", 3 => "Activity"}
4
4
  end
@@ -0,0 +1,17 @@
1
+ class CreatePlantTable < ActiveRecord::Migration[5.2]
2
+
3
+ def up
4
+ create_table :plants do |t|
5
+ t.string :name
6
+ t.string :type
7
+ t.string :kind
8
+ t.integer :owner_id
9
+ end
10
+ end
11
+
12
+ def down
13
+ drop_table :plants
14
+ end
15
+
16
+ end
17
+
@@ -0,0 +1,15 @@
1
+ class CreateActivityTable < ActiveRecord::Migration[5.2]
2
+
3
+ def up
4
+ create_table :activities do |t|
5
+ t.string :name
6
+ end
7
+ end
8
+
9
+ def down
10
+ drop_table :activities
11
+ end
12
+
13
+ end
14
+
15
+
@@ -0,0 +1,11 @@
1
+ module Namespaced
2
+ class Activity < ActiveRecord::Base
3
+ include PolymorphicIntegerType::Extensions
4
+
5
+ self.store_full_sti_class = false
6
+ self.table_name = "activities"
7
+
8
+ has_many :target_links, as: :target, inverse_of: :target, integer_type: true, class_name: "Link"
9
+ end
10
+ end
11
+
@@ -3,5 +3,9 @@ module Namespaced
3
3
 
4
4
  self.store_full_sti_class = false
5
5
  self.table_name = "animals"
6
+
7
+ def self.polymorphic_name
8
+ "Animal"
9
+ end
6
10
  end
7
- end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Namespaced
2
+ class Plant < ActiveRecord::Base
3
+ include PolymorphicIntegerType::Extensions
4
+
5
+ self.store_full_sti_class = false
6
+ self.table_name = "plants"
7
+
8
+ belongs_to :owner, class_name: "Person"
9
+ has_many :source_links, as: :source, inverse_of: :source, integer_type: true, class_name: "Link"
10
+ end
11
+ end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: polymorphic_integer_type
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.2
4
+ version: 2.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kyle d'Oliveira
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-05 00:00:00.000000000 Z
11
+ date: 2020-11-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "<"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '6'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "<"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: '6'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: byebug
84
+ name: pry-byebug
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -108,11 +108,22 @@ files:
108
108
  - README.md
109
109
  - Rakefile
110
110
  - bin/setup
111
+ - gemfiles/Gemfile.rails-4.2-stable
112
+ - gemfiles/Gemfile.rails-4.2-stable.lock
113
+ - gemfiles/Gemfile.rails-5.0-stable
114
+ - gemfiles/Gemfile.rails-5.0-stable.lock
115
+ - gemfiles/Gemfile.rails-5.1-stable
116
+ - gemfiles/Gemfile.rails-5.1-stable.lock
117
+ - gemfiles/Gemfile.rails-5.2-stable
118
+ - gemfiles/Gemfile.rails-5.2-stable.lock
111
119
  - lib/polymorphic_integer_type.rb
120
+ - lib/polymorphic_integer_type/activerecord_4/predicate_builder_extension.rb
121
+ - lib/polymorphic_integer_type/activerecord_5_0_0/association_query_handler_extension.rb
122
+ - lib/polymorphic_integer_type/activerecord_5_0_0/polymorphic_array_value_extension.rb
123
+ - lib/polymorphic_integer_type/belongs_to_polymorphic_association_extension.rb
112
124
  - lib/polymorphic_integer_type/extensions.rb
113
125
  - lib/polymorphic_integer_type/mapping.rb
114
- - lib/polymorphic_integer_type/polymorphic_array_value_extension.rb
115
- - lib/polymorphic_integer_type/predicate_builder_extension.rb
126
+ - lib/polymorphic_integer_type/module_generator.rb
116
127
  - lib/polymorphic_integer_type/version.rb
117
128
  - polymorphic_integer_type.gemspec
118
129
  - spec/polymorphic_integer_type_spec.rb
@@ -129,7 +140,11 @@ files:
129
140
  - spec/support/migrations/3_create_person_table.rb
130
141
  - spec/support/migrations/4_create_food_table.rb
131
142
  - spec/support/migrations/5_create_drink_table.rb
143
+ - spec/support/migrations/6_create_plant_table.rb
144
+ - spec/support/migrations/7_create_activity_table.rb
145
+ - spec/support/namespaced_activity.rb
132
146
  - spec/support/namespaced_animal.rb
147
+ - spec/support/namespaced_plant.rb
133
148
  - spec/support/person.rb
134
149
  homepage: ''
135
150
  licenses:
@@ -151,7 +166,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
151
166
  version: '0'
152
167
  requirements: []
153
168
  rubyforge_project:
154
- rubygems_version: 2.6.14
169
+ rubygems_version: 2.7.9
155
170
  signing_key:
156
171
  specification_version: 4
157
172
  summary: Use integers rather than strings for the _type field
@@ -170,5 +185,9 @@ test_files:
170
185
  - spec/support/migrations/3_create_person_table.rb
171
186
  - spec/support/migrations/4_create_food_table.rb
172
187
  - spec/support/migrations/5_create_drink_table.rb
188
+ - spec/support/migrations/6_create_plant_table.rb
189
+ - spec/support/migrations/7_create_activity_table.rb
190
+ - spec/support/namespaced_activity.rb
173
191
  - spec/support/namespaced_animal.rb
192
+ - spec/support/namespaced_plant.rb
174
193
  - spec/support/person.rb
@@ -1,20 +0,0 @@
1
- module PolymorphicIntegerType
2
- module PolymorphicArrayValueExtension
3
- def type_to_ids_mapping
4
- super.tap do |result|
5
- association = @associated_table.send(:association)
6
- klass = association.active_record
7
- name = association.name
8
-
9
- if klass.respond_to?("#{name}_type_mapping")
10
- result.transform_keys! do |key|
11
- klass.send("#{name}_type_mapping").key(key)
12
- end
13
- end
14
- result
15
- end
16
- end
17
- end
18
- end
19
-
20
- ActiveRecord::PredicateBuilder::PolymorphicArrayValue.prepend(PolymorphicIntegerType::PolymorphicArrayValueExtension)