adaptive_alias 0.0.1 → 0.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: 6f96c867d9849406b6dc38c2d535e6ecf1e62d4de7793d79e78e474588467fc6
4
- data.tar.gz: f1b3ff5b3be19513a263212e98c80423f40955af50f744d7f4958202dfaf8659
3
+ metadata.gz: 81757ab8f4098990940d499ee2286c8c831fdac6462dfcafcd59b868ff596ec2
4
+ data.tar.gz: b88816e4745352dc63fb29a4d102a52935538bd0f5ef5591f8ce56e9057dc9d5
5
5
  SHA512:
6
- metadata.gz: 3f8f92726071ac5e064dadc6c9aeb96dc72ed3d99c98fe982988405ce1336cf7978a9720dff958e9555464f9edd791370056ce4dec6190d707f06d77c349c686
7
- data.tar.gz: 4d70ffe7088a940742a5c0cd12b0ee6f0249abe6c9cd75c162f0e277cf1066ca086ad8e28d4a6253c2cb103bc9e512e068be498d11305ea1b0563818a8100f30
6
+ metadata.gz: 60cb4e6e2f31787f93f6edf5415bd3fbe283999c50d0fba89d9e48e055a5c06ca7479ee8a158ec4618453352bc8034a18e9acbafae5905f4e4f2a7a0ee8ba54f
7
+ data.tar.gz: e80d6cdd3e41254d07e70e4440bc120b6940bfddb31f54709e97becafc18dd4eef2341832fc049d750e247e002a8097f4d9128697de0f657c8fdd1b47310d103
data/.rubocop.yml CHANGED
@@ -222,9 +222,9 @@ Metrics/CyclomaticComplexity:
222
222
  Enabled: true
223
223
 
224
224
  Layout/LineLength:
225
- Description: 'Limit lines to 120 characters.'
225
+ Description: 'Limit lines to 160 characters.'
226
226
  StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#80-character-limits'
227
- Max: 120
227
+ Max: 160
228
228
  Enabled: true
229
229
  Exclude:
230
230
  - 'config/locales/**'
data/CHANGELOG.md CHANGED
@@ -1 +1,10 @@
1
- ## Change Log
1
+ ## Change Log
2
+
3
+ ### [v0.0.3](https://github.com/khiav223577/adaptive_alias/compare/v0.0.2...v0.0.3) 2022/07/27
4
+ - [#3](https://github.com/khiav223577/adaptive_alias/pull/3) Fix: prevent calling custom column names from raising missing attributes (@khiav223577)
5
+
6
+ ### [v0.0.2](https://github.com/khiav223577/adaptive_alias/compare/v0.0.1...v0.0.2) 2022/07/26
7
+ - [#2](https://github.com/khiav223577/adaptive_alias/pull/2) Doesn't need rails_compatibility in runtime (@khiav223577)
8
+
9
+ ### v0.0.1 2022/07/22
10
+ - [#1](https://github.com/khiav223577/adaptive_alias/pull/1) Implement adaptive_alias features (@khiav223577)
data/README.md CHANGED
@@ -8,6 +8,27 @@
8
8
 
9
9
  Extend attribute_alias and make it be adaptive with realtime database schema.
10
10
 
11
+ When we are going to rename a column, we may want to add a forward-patch so that we can use new column name before migration. And after migration, we may want to add a backward-patch so that those where are still using old column name will not be broken.
12
+ Ideally, we switch from forward-patch to backward-patch right after migration:
13
+ ```rb
14
+ ForwardPatch migrate BackwardPatch
15
+ |----------------------------------------|----------------------------------------|
16
+
17
+ ```
18
+
19
+ But in reality, it will take times to deploy and restart server to switch patch. There is a gap between migration and restart. So what will happen when db is migrated but server is not restarted?
20
+ We need a way to automatically adjust the patch to adapt current schema.
21
+
22
+ ```rb
23
+ ForwardPatch migrate restart BackwardPatch
24
+ |----------------------------------------|---@-----|-------------------------------|
25
+
26
+ ```
27
+
28
+ This is what this gem wants to achieve. We don't want to do complex migrations, take care of backward-compatibiliy, and have any downtime.
29
+ Just rely on this gem.
30
+
31
+
11
32
  ## Supports
12
33
  - Ruby 2.6 ~ 2.7, 3.0 ~ 3.1
13
34
  - Rails 6.0, 6.1, 7.0
@@ -38,8 +38,7 @@ Gem::Specification.new do |spec|
38
38
  spec.add_development_dependency 'rake', '~> 12.0'
39
39
  spec.add_development_dependency 'sqlite3', '~> 1.3'
40
40
  spec.add_development_dependency 'minitest', '~> 5.0'
41
- spec.add_development_dependency 'backports', '~> 3.15.0'
41
+ spec.add_development_dependency 'rails_compatibility', '>= 0.0.8'
42
42
 
43
43
  spec.add_dependency 'activerecord', '>= 3'
44
- spec.add_dependency 'rails_compatibility', '>= 0.0.8'
45
44
  end
data/gemfiles/6.0.gemfile CHANGED
@@ -5,6 +5,7 @@ gem 'activerecord', '~> 6.0.0'
5
5
  group :test do
6
6
  gem 'simplecov', '< 0.18'
7
7
  gem 'mysql2', '0.5.3'
8
+ gem 'acts-as-taggable-on', '~> 7.0.0'
8
9
  end
9
10
 
10
11
  gemspec path: '../'
data/gemfiles/6.1.gemfile CHANGED
@@ -5,6 +5,7 @@ gem 'activerecord', '~> 6.1.3'
5
5
  group :test do
6
6
  gem 'simplecov', '< 0.18'
7
7
  gem 'mysql2', '0.5.3'
8
+ gem 'acts-as-taggable-on', '~> 7.0.0'
8
9
  end
9
10
 
10
11
  gemspec path: '../'
data/gemfiles/7.0.gemfile CHANGED
@@ -6,6 +6,7 @@ gem 'activerecord', '~> 7.0.0'
6
6
  group :test do
7
7
  gem 'simplecov', '< 0.18'
8
8
  gem 'mysql2', '0.5.3'
9
+ gem 'acts-as-taggable-on', '~> 9.0.0'
9
10
  end
10
11
 
11
12
  gemspec path: '../'
@@ -9,12 +9,14 @@ module ActiveRecord::AttributeMethods::Read
9
9
  _read_attribute(name, &block)
10
10
  end
11
11
 
12
+ # This method exists to avoid the expensive primary_key check internally, without
13
+ # breaking compatibility with the write_attribute API
12
14
  def _read_attribute(attr_name, &block) # :nodoc:
13
15
  name = attr_name.to_s
14
16
  name = self.class.attribute_aliases[name] || name
15
17
 
16
18
  sync_with_transaction_state if @transaction_state&.finalized?
17
- return yield if block_given? && !@attributes.key?(name)
18
- @attributes.fetch_value(name, &block)
19
+ return yield(name) if block_given? and AdaptiveAlias.missing_value?(@attributes, self.class, name)
20
+ return @attributes.fetch_value(name, &block)
19
21
  end
20
22
  end
@@ -3,19 +3,10 @@ require 'active_model'
3
3
  module ActiveModel::AttributeMethods
4
4
  module ClassMethods
5
5
  def remove_proxy_call(mod, name)
6
- defn = if NAME_COMPILABLE_REGEXP.match?(name)
7
- "undef #{name}"
8
- else
9
- "remove_method(:'#{name}')"
10
- end
11
-
12
- mod.module_eval defn, __FILE__, __LINE__ + 1
6
+ mod.module_eval "remove_method(:'#{name}')", __FILE__, __LINE__ + 1
13
7
  end
14
8
 
15
9
  def remove_alias_attribute(new_name)
16
- # association_scope -> add_constraints -> last_chain_scope -> where!(key => model[foreign_key])
17
- # self[attr_name] -> read_attribute(attr_name) -> attribute_aliases
18
- # where! -> where_clause_factory.build -> attributes = predicate_builder.resolve_column_aliases(opts) -> attribute_aliases
19
10
  self.attribute_aliases = attribute_aliases.except(new_name.to_s)
20
11
 
21
12
  attribute_method_matchers.each do |matcher|
@@ -0,0 +1,22 @@
1
+ require 'active_record'
2
+
3
+ module ActiveRecord::AttributeMethods::Write
4
+ def write_attribute(attr_name, value)
5
+ name = attr_name.to_s
6
+ name = self.class.attribute_aliases[name] || name
7
+
8
+ name = @primary_key if name == 'id' && @primary_key
9
+ _write_attribute(name, value)
10
+ end
11
+
12
+ # This method exists to avoid the expensive primary_key check internally, without
13
+ # breaking compatibility with the write_attribute API
14
+ def _write_attribute(attr_name, value) # :nodoc:
15
+ name = attr_name.to_s
16
+ name = self.class.attribute_aliases[name] || name
17
+
18
+ sync_with_transaction_state if @transaction_state&.finalized?
19
+ @attributes.write_from_user(name, value)
20
+ value
21
+ end
22
+ end
@@ -4,6 +4,10 @@ module AdaptiveAlias
4
4
  def find_target(*)
5
5
  AdaptiveAlias.rescue_statement_invalid(nil){ super }
6
6
  end
7
+
8
+ def create!(attributes = {}, &block)
9
+ AdaptiveAlias.rescue_statement_invalid(association_scope){ super }
10
+ end
7
11
  end
8
12
  end
9
13
  end
@@ -1,13 +1,13 @@
1
- module AdaptiveAlias
2
- module Hooks
3
- module AssociationScope
4
- def last_chain_scope(*)
5
- AdaptiveAlias.rescue_missing_attribute{ super }
6
- end
7
- end
8
- end
9
- end
10
-
11
- class ActiveRecord::Associations::AssociationScope
12
- prepend AdaptiveAlias::Hooks::AssociationScope
13
- end
1
+ module AdaptiveAlias
2
+ module Hooks
3
+ module AssociationScope
4
+ def last_chain_scope(_scope, reflection, owner)
5
+ AdaptiveAlias.rescue_missing_attribute(owner.class){ super }
6
+ end
7
+ end
8
+ end
9
+ end
10
+
11
+ class ActiveRecord::Associations::AssociationScope
12
+ prepend AdaptiveAlias::Hooks::AssociationScope
13
+ end
@@ -2,7 +2,7 @@ module AdaptiveAlias
2
2
  module Hooks
3
3
  module SingularAssociation
4
4
  def reader(*)
5
- AdaptiveAlias.rescue_missing_attribute{ super }
5
+ AdaptiveAlias.rescue_missing_attribute(owner.class){ super }
6
6
  end
7
7
  end
8
8
  end
@@ -4,7 +4,7 @@ require 'adaptive_alias/patches/base'
4
4
 
5
5
  module AdaptiveAlias
6
6
  module Patches
7
- class BackPatch < Base
7
+ class BackwardPatch < Base
8
8
  def apply!
9
9
  AdaptiveAlias.current_patches[[@klass, @old_column, @new_column]] = self
10
10
  @klass.alias_attribute(@old_column, @new_column)
@@ -14,6 +14,7 @@ module AdaptiveAlias
14
14
  def remove!
15
15
  super
16
16
  @klass.remove_alias_attribute(@old_column)
17
+ @klass.define_attribute_method(@old_column)
17
18
  ForwardPatch.new(@klass, @old_column, @new_column).apply!
18
19
  end
19
20
  end
@@ -6,6 +6,7 @@ module AdaptiveAlias
6
6
  attr_reader :fix_association
7
7
  attr_reader :fix_missing_attribute
8
8
  attr_reader :removed
9
+ attr_reader :removable
9
10
 
10
11
  def initialize(klass, old_column, new_column)
11
12
  @klass = klass
@@ -15,39 +16,65 @@ module AdaptiveAlias
15
16
 
16
17
  def add_hooks!(current_column:, alias_column:, log_warning: false)
17
18
  patch = self
19
+ klass = @klass
18
20
  old_column = @old_column
19
21
  new_column = @new_column
20
22
 
21
- AdaptiveAlias.get_or_create_model_module(@klass).instance_exec do
23
+ AdaptiveAlias.get_or_create_model_module(klass).instance_exec do
22
24
  remove_method(new_column) if method_defined?(new_column)
23
25
  define_method(new_column) do
24
- AdaptiveAlias.rescue_missing_attribute{ self[new_column] }
26
+ AdaptiveAlias.rescue_missing_attribute(klass){ self[new_column] }
27
+ end
28
+
29
+ remove_method("#{new_column}=") if method_defined?("#{new_column}=")
30
+ define_method("#{new_column}=") do |*args|
31
+ AdaptiveAlias.rescue_missing_attribute(klass){ super(*args) }
25
32
  end
26
33
 
27
34
  remove_method(old_column) if method_defined?(old_column)
28
35
  define_method(old_column) do
29
36
  patch.log_warning if log_warning
30
- AdaptiveAlias.rescue_missing_attribute{ self[old_column] }
37
+ AdaptiveAlias.rescue_missing_attribute(klass){ self[old_column] }
38
+ end
39
+
40
+ remove_method("#{old_column}=") if method_defined?("#{old_column}=")
41
+ define_method("#{old_column}=") do |*args|
42
+ patch.log_warning if log_warning
43
+ AdaptiveAlias.rescue_missing_attribute(klass){ super(*args) }
31
44
  end
32
45
  end
33
46
 
34
- expected_error_message = "Mysql2::Error: Unknown column '#{@klass.table_name}.#{current_column}' in 'where clause'".freeze
47
+ expected_association_err_msgs = [
48
+ "Mysql2::Error: Unknown column '#{klass.table_name}.#{current_column}' in 'where clause'".freeze,
49
+ "Mysql2::Error: Unknown column '#{current_column}' in 'field list'".freeze,
50
+ ].freeze
35
51
 
36
- @fix_missing_attribute = proc do
52
+ expected_attribute_err_msgs = [
53
+ "can't write unknown attribute `#{current_column}`".freeze,
54
+ "missing attribute: #{current_column}".freeze,
55
+ ].freeze
56
+
57
+ @fix_missing_attribute = proc do |error_klass, error|
58
+ next false if not patch.removable
37
59
  next false if patch.removed
60
+ next false if klass != error_klass
61
+ next false if not expected_attribute_err_msgs.include?(error.message)
38
62
 
39
63
  patch.remove!
40
64
  next true
41
65
  end
42
66
 
43
67
  @fix_association = proc do |target, error|
44
- next false if patch.removed || error.message != expected_error_message
68
+ next false if not patch.removable
69
+ next false if patch.removed
70
+ next false if not expected_association_err_msgs.include?(error.message)
45
71
 
46
72
  patch.remove!
47
73
 
48
74
  if target
49
75
  hash = target.where_values_hash
50
76
  hash[alias_column] = hash.delete(current_column) if hash.key?(current_column)
77
+ hash[alias_column.to_s] = hash.delete(current_column.to_s) if hash.key?(current_column.to_s)
51
78
  target.instance_variable_set(:@arel, nil)
52
79
  target.unscope!(:where).where!(hash)
53
80
  end
@@ -57,7 +84,7 @@ module AdaptiveAlias
57
84
  end
58
85
 
59
86
  def log_warning
60
- if @prev_warning_time == nil || @prev_warning_time < AdaptiveAlias.log_interval.ago
87
+ if @prev_warning_time == nil || @prev_warning_time < Time.now - AdaptiveAlias.log_interval
61
88
  @prev_warning_time = Time.now
62
89
  AdaptiveAlias.unexpected_old_column_proc&.call
63
90
  end
@@ -65,11 +92,15 @@ module AdaptiveAlias
65
92
 
66
93
  def remove!
67
94
  @removed = true
68
- @klass.send(:reload_schema_from_cache)
69
- @klass.initialize_find_by_cache
95
+ @klass.reset_column_information
96
+ @klass.columns_hash
70
97
  @fix_association = nil
71
98
  @fix_missing_attribute = nil
72
99
  end
100
+
101
+ def mark_removable
102
+ @removable = true
103
+ end
73
104
  end
74
105
  end
75
106
  end
@@ -14,7 +14,8 @@ module AdaptiveAlias
14
14
  def remove!
15
15
  super
16
16
  @klass.remove_alias_attribute(@new_column)
17
- BackPatch.new(@klass, @old_column, @new_column).apply!
17
+ @klass.define_attribute_method(@new_column)
18
+ BackwardPatch.new(@klass, @old_column, @new_column).apply!
18
19
  end
19
20
  end
20
21
  end
@@ -1,3 +1,3 @@
1
1
  module AdaptiveAlias
2
- VERSION = '0.0.1'
2
+ VERSION = '0.1.0'
3
3
  end
@@ -1,65 +1,78 @@
1
- # frozen_string_literal: true
2
-
3
- require 'adaptive_alias/version'
4
- require 'adaptive_alias/active_model_patches/read_attribute'
5
- require 'adaptive_alias/active_model_patches/remove_alias_attribute'
6
- require 'adaptive_alias/patches/back_patch'
7
- require 'adaptive_alias/patches/forward_patch'
8
-
9
- require 'adaptive_alias/hooks/association'
10
- require 'adaptive_alias/hooks/association_scope'
11
- require 'adaptive_alias/hooks/singular_association'
12
- require 'adaptive_alias/hooks/relation'
13
-
14
- module AdaptiveAlias
15
- @log_interval = 10 * 60
16
- @current_patches = {}
17
- @model_modules ||= {}
18
-
19
- class << self
20
- attr_accessor :unexpected_old_column_proc
21
- attr_accessor :log_interval
22
- attr_accessor :current_patches
23
- end
24
-
25
- class << self
26
- def [](old_column, new_column)
27
- old_column = old_column.to_sym
28
- new_column = new_column.to_sym
29
-
30
- Module.new do
31
- extend ActiveSupport::Concern
32
-
33
- included do
34
- if column_names.include?(new_column)
35
- Patches::BackPatch.new(self, old_column, new_column).apply!
36
- else
37
- Patches::ForwardPatch.new(self, old_column, new_column).apply!
38
- end
39
- end
40
- end
41
- end
42
-
43
- def rescue_statement_invalid(relation)
44
- yield
45
- rescue ActiveRecord::StatementInvalid => error
46
- raise error if AdaptiveAlias.current_patches.all?{|_key, patch| !patch.fix_association.call(relation, error) }
47
- retry
48
- end
49
-
50
- def rescue_missing_attribute
51
- yield
52
- rescue ActiveModel::MissingAttributeError => error
53
- raise error if AdaptiveAlias.current_patches.all?{|_key, patch| !patch.fix_missing_attribute.call }
54
- retry
55
- end
56
-
57
- def get_or_create_model_module(klass)
58
- return @model_modules[klass] if @model_modules[klass]
59
-
60
- @model_modules[klass] = Module.new
61
- klass.prepend(@model_modules[klass])
62
- return @model_modules[klass]
63
- end
64
- end
65
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'adaptive_alias/version'
4
+ require 'adaptive_alias/active_model_patches/read_attribute'
5
+ require 'adaptive_alias/active_model_patches/write_attribute'
6
+ require 'adaptive_alias/active_model_patches/remove_alias_attribute'
7
+ require 'adaptive_alias/patches/backward_patch'
8
+ require 'adaptive_alias/patches/forward_patch'
9
+
10
+ require 'adaptive_alias/hooks/association'
11
+ require 'adaptive_alias/hooks/association_scope'
12
+ require 'adaptive_alias/hooks/singular_association'
13
+ require 'adaptive_alias/hooks/relation'
14
+
15
+ module AdaptiveAlias
16
+ @log_interval = 10 * 60
17
+ @current_patches = {}
18
+ @model_modules ||= {}
19
+
20
+ class << self
21
+ attr_accessor :unexpected_old_column_proc
22
+ attr_accessor :log_interval
23
+ attr_accessor :current_patches
24
+ end
25
+
26
+ class << self
27
+ def [](old_column, new_column)
28
+ old_column = old_column.to_sym
29
+ new_column = new_column.to_sym
30
+
31
+ Module.new do
32
+ extend ActiveSupport::Concern
33
+
34
+ included do
35
+ patch = (column_names.include?(new_column) ? Patches::BackwardPatch : Patches::ForwardPatch).new(self, old_column, new_column)
36
+ patch.apply!
37
+ patch.mark_removable
38
+ end
39
+ end
40
+ end
41
+
42
+ def rescue_statement_invalid(relation, &block)
43
+ yield
44
+ rescue ActiveRecord::StatementInvalid => error
45
+ raise error if AdaptiveAlias.current_patches.all?{|_key, patch| !patch.fix_association.call(relation, error) }
46
+
47
+ result = rescue_statement_invalid(relation, &block)
48
+ AdaptiveAlias.current_patches.each_value(&:mark_removable)
49
+ return result
50
+ end
51
+
52
+ def rescue_missing_attribute(klass, &block)
53
+ yield
54
+ rescue ActiveModel::MissingAttributeError => error
55
+ raise error if AdaptiveAlias.current_patches.all?{|_key, patch| !patch.fix_missing_attribute.call(klass, error) }
56
+
57
+ result = rescue_missing_attribute(klass, &block)
58
+ AdaptiveAlias.current_patches.each_value(&:mark_removable)
59
+ return result
60
+ end
61
+
62
+ def get_or_create_model_module(klass)
63
+ return @model_modules[klass] if @model_modules[klass]
64
+
65
+ @model_modules[klass] = Module.new
66
+ klass.prepend(@model_modules[klass])
67
+ return @model_modules[klass]
68
+ end
69
+
70
+ def missing_value?(attributes, klass, name)
71
+ return false if attributes.key?(name)
72
+
73
+ old_name = klass.attribute_aliases.key(name)
74
+ return false if old_name == nil
75
+ return !!AdaptiveAlias.current_patches[[klass, old_name.to_sym, name.to_sym]]
76
+ end
77
+ end
78
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: adaptive_alias
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - khiav reoy
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-07-22 00:00:00.000000000 Z
11
+ date: 2022-08-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -73,19 +73,19 @@ dependencies:
73
73
  - !ruby/object:Gem::Version
74
74
  version: '5.0'
75
75
  - !ruby/object:Gem::Dependency
76
- name: backports
76
+ name: rails_compatibility
77
77
  requirement: !ruby/object:Gem::Requirement
78
78
  requirements:
79
- - - "~>"
79
+ - - ">="
80
80
  - !ruby/object:Gem::Version
81
- version: 3.15.0
81
+ version: 0.0.8
82
82
  type: :development
83
83
  prerelease: false
84
84
  version_requirements: !ruby/object:Gem::Requirement
85
85
  requirements:
86
- - - "~>"
86
+ - - ">="
87
87
  - !ruby/object:Gem::Version
88
- version: 3.15.0
88
+ version: 0.0.8
89
89
  - !ruby/object:Gem::Dependency
90
90
  name: activerecord
91
91
  requirement: !ruby/object:Gem::Requirement
@@ -100,20 +100,6 @@ dependencies:
100
100
  - - ">="
101
101
  - !ruby/object:Gem::Version
102
102
  version: '3'
103
- - !ruby/object:Gem::Dependency
104
- name: rails_compatibility
105
- requirement: !ruby/object:Gem::Requirement
106
- requirements:
107
- - - ">="
108
- - !ruby/object:Gem::Version
109
- version: 0.0.8
110
- type: :runtime
111
- prerelease: false
112
- version_requirements: !ruby/object:Gem::Requirement
113
- requirements:
114
- - - ">="
115
- - !ruby/object:Gem::Version
116
- version: 0.0.8
117
103
  description: Extend attribute_alias and make it be adaptive with realtime database
118
104
  schema
119
105
  email:
@@ -139,11 +125,12 @@ files:
139
125
  - lib/adaptive_alias.rb
140
126
  - lib/adaptive_alias/active_model_patches/read_attribute.rb
141
127
  - lib/adaptive_alias/active_model_patches/remove_alias_attribute.rb
128
+ - lib/adaptive_alias/active_model_patches/write_attribute.rb
142
129
  - lib/adaptive_alias/hooks/association.rb
143
130
  - lib/adaptive_alias/hooks/association_scope.rb
144
131
  - lib/adaptive_alias/hooks/relation.rb
145
132
  - lib/adaptive_alias/hooks/singular_association.rb
146
- - lib/adaptive_alias/patches/back_patch.rb
133
+ - lib/adaptive_alias/patches/backward_patch.rb
147
134
  - lib/adaptive_alias/patches/base.rb
148
135
  - lib/adaptive_alias/patches/forward_patch.rb
149
136
  - lib/adaptive_alias/version.rb