store_base_sti_class 2.0.3 → 3.1.0

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