polymorphic_integer_type 2.2.2 → 2.3.1

Sign up to get free protection for your applications and to get access to all the features.
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)