store_base_sti_class 2.0.3 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5e65e14ac35f409bec5e78c411a0b3fac80ca189d8e77f693fc2ecc9f4cf609d
4
- data.tar.gz: c0aabbee8bba07b1818f5f2fca9f94a916f56e29bcff73d9f1919fa53d269bcc
3
+ metadata.gz: 4e52e07f6f052e37a3b9a46da10810e6cab0dea2b45f5c84fa78ee661374d8e4
4
+ data.tar.gz: 743fb6c76c85b8ac6c4fa6d7216e39c37b73a3b3143eec2efea43994d4da61bf
5
5
  SHA512:
6
- metadata.gz: 6078f16de9958cead9799a9da35830c2c031c17bbead961b801f6194905e65e43ab6f002ab34fd34ef6431e0b8f9ab1fc52b0c502372a3957a768480459df882
7
- data.tar.gz: 22e514b7f2ce662d2cfa8f8fe6b2bc62f4491defe8b182c76121922f01ca7929146f546cfb7eab0d8d42ba8417c4343ae54d616cb949a44bba48c98fa5b0469f
6
+ metadata.gz: b88e7535394b002c2041545dfd13a6cdd74aa7ae928e986e09eda605ece8d189370754763eb674f775be9e19698edb36bd2304dfa0db3f1849a1f7b83c7c17b1
7
+ data.tar.gz: 77653c6b771bb6a8db2ae1fd0d2c3ffdb9a1cef93cf0907a2f1f70bfe333282c494dd05f2b0d7860f04749b3ec770eb0443b6ef3a15ae4ab702717fb14e7225a
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2011-2019 AppFolio, inc.
1
+ Copyright (c) 2011-2023 AppFolio, Inc
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -1,3 +1,3 @@
1
1
  module StoreBaseSTIClass
2
- VERSION = '2.0.3'.freeze
2
+ VERSION = '3.1.0'.freeze
3
3
  end
@@ -1,15 +1,156 @@
1
1
  require 'active_record'
2
2
 
3
- if ActiveRecord::VERSION::STRING =~ /^5\.0/
4
- require 'store_base_sti_class_for_5_0'
5
- elsif ActiveRecord::VERSION::STRING =~ /^5\.1/
6
- require 'store_base_sti_class_for_5_1'
7
- elsif ActiveRecord::VERSION::STRING =~ /^5\.2/
8
- require 'store_base_sti_class_for_5_2'
9
- elsif ActiveRecord::VERSION::STRING =~ /^6\.0/
10
- require 'store_base_sti_class_for_6_0'
11
- elsif ActiveRecord::VERSION::STRING =~ /^6\.1/
12
- require 'store_base_sti_class_for_6_1'
3
+ require 'active_record/associations/join_dependency/join_part'
4
+
5
+ module ActiveRecord
6
+ class Base
7
+ class_attribute :store_base_sti_class
8
+ self.store_base_sti_class = true
9
+ end
10
+
11
+ module Inheritance
12
+ module ClassMethods
13
+ def polymorphic_name
14
+ ActiveRecord::Base.store_base_sti_class ? base_class.name : name
15
+ end
16
+ end
17
+ end
18
+
19
+ module Associations
20
+ class Preloader
21
+ class ThroughAssociation < Association
22
+ private
23
+
24
+ def through_scope
25
+ scope = through_reflection.klass.unscoped
26
+ options = reflection.options
27
+
28
+ values = reflection_scope.values
29
+ if annotations = values[:annotate]
30
+ scope.annotate!(*annotations)
31
+ end
32
+
33
+ if options[:source_type]
34
+ # BEGIN PATCH
35
+ # original:
36
+ # scope.where! reflection.foreign_type => options[:source_type]
37
+
38
+ adjusted_foreign_type =
39
+ if ActiveRecord::Base.store_base_sti_class
40
+ options[:source_type]
41
+ else
42
+ ([options[:source_type].constantize] + options[:source_type].constantize.descendants).map(&:to_s)
43
+ end
44
+
45
+ scope.where! reflection.foreign_type => adjusted_foreign_type
46
+ # END PATCH
47
+
48
+ elsif !reflection_scope.where_clause.empty?
49
+ scope.where_clause = reflection_scope.where_clause
50
+
51
+ if includes = values[:includes]
52
+ scope.includes!(source_reflection.name => includes)
53
+ else
54
+ scope.includes!(source_reflection.name)
55
+ end
56
+
57
+ if values[:references] && !values[:references].empty?
58
+ scope.references_values |= values[:references]
59
+ else
60
+ scope.references!(source_reflection.table_name)
61
+ end
62
+
63
+ if joins = values[:joins]
64
+ scope.joins!(source_reflection.name => joins)
65
+ end
66
+
67
+ if left_outer_joins = values[:left_outer_joins]
68
+ scope.left_outer_joins!(source_reflection.name => left_outer_joins)
69
+ end
70
+
71
+ if scope.eager_loading? && order_values = values[:order]
72
+ scope = scope.order(order_values)
73
+ end
74
+ end
75
+
76
+ scope
77
+ end
78
+ end
79
+ end
80
+
81
+ class AssociationScope
82
+ private
83
+
84
+ def next_chain_scope(scope, reflection, next_reflection)
85
+ primary_key = reflection.join_primary_key
86
+ foreign_key = reflection.join_foreign_key
87
+
88
+ table = reflection.aliased_table
89
+ foreign_table = next_reflection.aliased_table
90
+ constraint = table[primary_key].eq(foreign_table[foreign_key])
91
+
92
+ if reflection.type
93
+ # BEGIN PATCH
94
+ # original:
95
+ # value = transform_value(next_reflection.klass.polymorphic_name)
96
+ # scope = apply_scope(scope, table, reflection.type, value)
97
+
98
+ if ActiveRecord::Base.store_base_sti_class
99
+ value = transform_value(next_reflection.klass.polymorphic_name)
100
+ else
101
+ klass = next_reflection.klass
102
+ value = ([klass] + klass.descendants).map(&:name)
103
+ end
104
+ scope = apply_scope(scope, table, reflection.type, value)
105
+ # END PATCH
106
+ end
107
+
108
+ scope.joins!(join(foreign_table, constraint))
109
+ end
110
+
111
+ end
112
+
113
+ class HasManyThroughAssociation
114
+ private
115
+
116
+ def build_through_record(record)
117
+ @through_records[record.object_id] ||= begin
118
+ ensure_mutable
119
+
120
+ attributes = through_scope_attributes
121
+ attributes[source_reflection.name] = record
122
+
123
+ # START PATCH
124
+ if ActiveRecord::Base.store_base_sti_class
125
+ attributes[source_reflection.foreign_type] = options[:source_type] if options[:source_type]
126
+ end
127
+ # END PATCH
128
+
129
+ through_association.build(attributes)
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ module Reflection
136
+ class PolymorphicReflection
137
+ def source_type_scope
138
+ type = @previous_reflection.foreign_type
139
+ source_type = @previous_reflection.options[:source_type]
140
+
141
+ # START PATCH
142
+ adjusted_source_type =
143
+ if ActiveRecord::Base.store_base_sti_class
144
+ source_type
145
+ else
146
+ ([source_type.constantize] + source_type.constantize.descendants).map(&:to_s)
147
+ end
148
+ # END PATCH
149
+
150
+ lambda { |object| where(type => adjusted_source_type) }
151
+ end
152
+ end
153
+ end
13
154
  end
14
155
 
15
156
  module StoreBaseSTIClass
@@ -1,29 +1,30 @@
1
- # -*- encoding: utf-8 -*-
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'store_base_sti_class/version'
1
+ # frozen_string_literal: true
5
2
 
6
- Gem::Specification.new do |s|
7
- s.name = 'store_base_sti_class'
8
- s.version = StoreBaseSTIClass::VERSION
3
+ require_relative 'lib/store_base_sti_class/version'
9
4
 
10
- s.require_paths = ['lib']
11
- s.authors = ['AppFolio']
12
- s.description = "\n ActiveRecord has always stored the base class in polymorphic _type columns when using STI. This can have non-trivial\n performance implications in certain cases. This gem adds the 'store_base_sti_class' configuration option which controls\n whether ActiveRecord will store the base class or the actual class. Defaults to true for backwards compatibility.\n "
13
- s.email = 'engineering@appfolio.com'
14
- s.extra_rdoc_files = %w(
15
- LICENSE.txt
16
- README.md
17
- )
18
- s.files = Dir['**/*'].reject{ |f| f[%r{^pkg/}] || f[%r{^test/}] }
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'store_base_sti_class'
7
+ spec.version = StoreBaseSTIClass::VERSION
8
+ spec.platform = Gem::Platform::RUBY
9
+ spec.author = 'AppFolio'
10
+ spec.email = 'opensource@appfolio.com'
11
+ spec.description = <<~MSG
12
+ ActiveRecord has always stored the base class in polymorphic _type columns when using STI. This can have non-trivial
13
+ performance implications in certain cases. This gem adds the 'store_base_sti_class' configuration option which
14
+ controls whether ActiveRecord will store the base class or the actual class. Defaults to true for backwards
15
+ compatibility.'
16
+ MSG
17
+ spec.summary = <<~MSG
18
+ Modifies ActiveRecord 6.1.x - 7.1.x with the ability to store the actual class (instead of the base class) in
19
+ polymorhic _type columns when using STI.
20
+ MSG
21
+ spec.homepage = 'https://github.com/appfolio/store_base_sti_class'
22
+ spec.license = 'MIT'
23
+ spec.files = Dir['**/*'].select { |f| f[%r{^(lib/|LICENSE.txt|.*gemspec)}] }
24
+ spec.require_paths = ['lib']
25
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.6.3')
19
26
 
20
- s.homepage = 'http://github.com/appfolio/store_base_sti_class'
21
- s.licenses = ['MIT']
22
- s.rubygems_version = '2.2.2'
23
- s.summary = 'Modifies ActiveRecord 4.2.x - 6.0.x with the ability to store the actual class (instead of the base class) in polymorhic _type columns when using STI'
27
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
24
28
 
25
- s.add_runtime_dependency(%q<activerecord>, ['>= 4.0'])
26
- s.add_development_dependency(%q<minitest>, ['>= 4.0'])
27
- s.add_development_dependency(%q<appraisal>, ['>= 0'])
28
- s.add_development_dependency(%q<bundler>, ['>= 0'])
29
+ spec.add_dependency('activerecord', ['>= 6.1', '< 7.2'])
29
30
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: store_base_sti_class
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - AppFolio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-31 00:00:00.000000000 Z
11
+ date: 2023-10-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,92 +16,39 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '4.0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '4.0'
27
- - !ruby/object:Gem::Dependency
28
- name: minitest
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '4.0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '4.0'
41
- - !ruby/object:Gem::Dependency
42
- name: appraisal
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
19
+ version: '6.1'
20
+ - - "<"
46
21
  - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
22
+ version: '7.2'
23
+ type: :runtime
49
24
  prerelease: false
50
25
  version_requirements: !ruby/object:Gem::Requirement
51
26
  requirements:
52
27
  - - ">="
53
28
  - !ruby/object:Gem::Version
54
- version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: bundler
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
29
+ version: '6.1'
30
+ - - "<"
67
31
  - !ruby/object:Gem::Version
68
- version: '0'
69
- description: "\n ActiveRecord has always stored the base class in polymorphic _type
70
- columns when using STI. This can have non-trivial\n performance implications
71
- in certain cases. This gem adds the 'store_base_sti_class' configuration option
72
- which controls\n whether ActiveRecord will store the base class or the actual
73
- class. Defaults to true for backwards compatibility.\n "
74
- email: engineering@appfolio.com
32
+ version: '7.2'
33
+ description: |
34
+ ActiveRecord has always stored the base class in polymorphic _type columns when using STI. This can have non-trivial
35
+ performance implications in certain cases. This gem adds the 'store_base_sti_class' configuration option which
36
+ controls whether ActiveRecord will store the base class or the actual class. Defaults to true for backwards
37
+ compatibility.'
38
+ email: opensource@appfolio.com
75
39
  executables: []
76
40
  extensions: []
77
- extra_rdoc_files:
78
- - LICENSE.txt
79
- - README.md
41
+ extra_rdoc_files: []
80
42
  files:
81
- - Appraisals
82
- - Gemfile
83
43
  - LICENSE.txt
84
- - README.md
85
- - Rakefile
86
- - gemfiles/rails_5.0.7.gemfile
87
- - gemfiles/rails_5.1.7.gemfile
88
- - gemfiles/rails_5.2.3.gemfile
89
- - gemfiles/rails_5.2.4.gemfile
90
- - gemfiles/rails_5.2.5.gemfile
91
- - gemfiles/rails_6.0.3.gemfile
92
- - gemfiles/rails_6.1.0.gemfile
93
44
  - lib/store_base_sti_class.rb
94
45
  - lib/store_base_sti_class/version.rb
95
- - lib/store_base_sti_class_for_5_0.rb
96
- - lib/store_base_sti_class_for_5_1.rb
97
- - lib/store_base_sti_class_for_5_2.rb
98
- - lib/store_base_sti_class_for_6_0.rb
99
- - lib/store_base_sti_class_for_6_1.rb
100
46
  - store_base_sti_class.gemspec
101
- homepage: http://github.com/appfolio/store_base_sti_class
47
+ homepage: https://github.com/appfolio/store_base_sti_class
102
48
  licenses:
103
49
  - MIT
104
- metadata: {}
50
+ metadata:
51
+ allowed_push_host: https://rubygems.org
105
52
  post_install_message:
106
53
  rdoc_options: []
107
54
  require_paths:
@@ -110,16 +57,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
110
57
  requirements:
111
58
  - - ">="
112
59
  - !ruby/object:Gem::Version
113
- version: '0'
60
+ version: 2.6.3
114
61
  required_rubygems_version: !ruby/object:Gem::Requirement
115
62
  requirements:
116
63
  - - ">="
117
64
  - !ruby/object:Gem::Version
118
65
  version: '0'
119
66
  requirements: []
120
- rubygems_version: 3.2.3
67
+ rubygems_version: 3.3.26
121
68
  signing_key:
122
69
  specification_version: 4
123
- summary: Modifies ActiveRecord 4.2.x - 6.0.x with the ability to store the actual
124
- class (instead of the base class) in polymorhic _type columns when using STI
70
+ summary: Modifies ActiveRecord 6.1.x - 7.1.x with the ability to store the actual
71
+ class (instead of the base class) in polymorhic _type columns when using STI.
125
72
  test_files: []
data/Appraisals DELETED
@@ -1,15 +0,0 @@
1
- RAILS_VERSIONS = %w[
2
- 5.0.7
3
- 5.1.7
4
- 5.2.3
5
- 5.2.4
6
- 6.0.3
7
- 6.1.0
8
- ].freeze
9
-
10
- RAILS_VERSIONS.each do |version|
11
- appraise "rails_#{version}" do
12
- gem 'activerecord', version
13
- gem 'sqlite3', ['6.0.3', '6.1.0'].include?(version) ? '~> 1.4.0' : '~> 1.3.0'
14
- end
15
- end
data/Gemfile DELETED
@@ -1,3 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gemspec
data/README.md DELETED
@@ -1,101 +0,0 @@
1
- [![CI](https://github.com/appfolio/store_base_sti_class/workflows/CI/badge.svg)](https://github.com/appfolio/store_base_sti_class/actions)
2
-
3
- ## Description
4
-
5
- Given the following class definitions:
6
-
7
- ```ruby
8
- class Address
9
- belongs_to :addressable, :polymorphic => true
10
- end
11
-
12
- class Person
13
- has_many :addresses, :as => addressable
14
- end
15
-
16
- class Vendor < Person
17
- end
18
- ```
19
-
20
- and given the following code:
21
-
22
- ```ruby
23
- vendor = Vendor.create(...)
24
- address = vendor.addresses.create(...)
25
-
26
- p vendor
27
- p address
28
- ```
29
-
30
- will output:
31
-
32
- ```ruby
33
- #<Vendor id: 1, type: "Vendor" ...>
34
- #<Address id: 1, addressable_id: 1, addressable_type: 'Person' ...>
35
- ```
36
-
37
- Notice that addressable_type column is Person even though the actual class is Vendor.
38
-
39
- Normally, this isn't a problem, however, it can have negative performance
40
- characteristics in certain circumstances. The most obvious one is that a join
41
- with persons or an extra query is required to find out the actual type of
42
- addressable.
43
-
44
- This gem adds the ActiveRecord::Base.store_base_sti_class configuration
45
- option. It defaults to true for backwards compatibility. Setting it to false
46
- will alter ActiveRecord's behavior to store the actual class in polymorphic
47
- _type columns when STI is used.
48
-
49
- In the example above, if the ActiveRecord::Base.store_base_sti_class is false, the output will be,
50
-
51
- ```
52
- #<Vendor id: 1, type: "Vendor" ...>
53
- #<Address id: 1, addressable_id: 1, addressable_type: 'Vendor' ...>
54
- ```
55
-
56
- ## Usage
57
-
58
- Add the following line to your Gemfile,
59
-
60
- ```ruby
61
- gem 'store_base_sti_class'
62
- ```
63
-
64
- then bundle install. Once you have the gem installed, add the following to one
65
- of the initializers (or make a new one) in config/initializers,
66
-
67
- ActiveRecord::Base.store_base_sti_class = false
68
-
69
- When changing this behavior, you will have write a migration to update all of
70
- your existing _type columns accordingly. You may also need to change your
71
- application if it explicitly relies on the _type columns.
72
-
73
- ## Notes
74
-
75
- This gem incorporates work from:
76
-
77
- - https://github.com/codepodu/store_base_sti_class_for_4_0
78
-
79
- It currently works with ActiveRecord 4.2.x through 6.0.x. If you need support
80
- for ActiveRecord 3.x, use a pre-1.0 version of the gem, or ActiveRecord < 4.2
81
- use a pre-2.0 version of the gem.
82
-
83
- ## Conflicts
84
-
85
- This gem produces known conflicts with these other gems:
86
-
87
- ### friendly_id
88
-
89
- When using [friendly_id](https://github.com/norman/friendly_id) >= 5.2.5 with the [History module](https://norman.github.io/friendly_id/FriendlyId/History.html) enabled, duplicate slugs will be generated for STI subclasses with the same sluggable identifier (ex: name). This will either cause saves to fail if you have the proper indexes in place, or will cause slug lookups to be non-deterministic, either of which is undesirable.
90
-
91
- ## History
92
-
93
- * https://github.com/rails/rails/issues/724
94
- * https://github.com/rails/rails/issues/5441#issuecomment-4563865
95
- * https://github.com/rails/rails/issues/4729#issuecomment-5729297
96
- * https://github.com/rails/rails/issues/5441#issuecomment-264871920
97
-
98
- ## Copyright
99
-
100
- Copyright (c) 2011-2019 AppFolio, inc. See LICENSE.txt for
101
- further details.
data/Rakefile DELETED
@@ -1,23 +0,0 @@
1
- require 'rubygems'
2
- require 'bundler'
3
-
4
- require 'appraisal'
5
-
6
- begin
7
- Bundler.setup(:default, :development)
8
- rescue Bundler::BundlerError => e
9
- $stderr.puts e.message
10
- $stderr.puts "Run `bundle install` to install missing gems"
11
- exit e.status_code
12
- end
13
- require 'rake'
14
-
15
- require 'rake/testtask'
16
- Rake::TestTask.new(:test) do |test|
17
- test.libs << 'lib' << 'test'
18
- test.pattern = 'test/**/test_*.rb'
19
- test.verbose = true
20
- end
21
-
22
- task :default => :test
23
-
@@ -1,8 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "activerecord", "5.0.7"
6
- gem "sqlite3", "~> 1.3.0"
7
-
8
- gemspec path: "../"
@@ -1,8 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "activerecord", "5.1.7"
6
- gem "sqlite3", "~> 1.3.0"
7
-
8
- gemspec path: "../"
@@ -1,8 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "activerecord", "5.2.3"
6
- gem "sqlite3", "~> 1.3.0"
7
-
8
- gemspec path: "../"
@@ -1,8 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "activerecord", "5.2.4"
6
- gem "sqlite3", "~> 1.3.0"
7
-
8
- gemspec path: "../"
@@ -1,8 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "activerecord", "5.2.5"
6
- gem "sqlite3", "~> 1.3.0"
7
-
8
- gemspec path: "../"
@@ -1,8 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "activerecord", "6.0.3"
6
- gem "sqlite3", "~> 1.4.0"
7
-
8
- gemspec path: "../"
@@ -1,8 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "activerecord", "6.1.0"
6
- gem "sqlite3", "~> 1.4.0"
7
-
8
- gemspec path: "../"