switchman 3.4.2 → 3.6.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +15 -14
  3. data/db/migrate/20180828183945_add_default_shard_index.rb +1 -1
  4. data/db/migrate/20190114212900_add_unique_name_indexes.rb +10 -4
  5. data/lib/switchman/active_record/abstract_adapter.rb +4 -2
  6. data/lib/switchman/active_record/associations.rb +89 -16
  7. data/lib/switchman/active_record/attribute_methods.rb +67 -22
  8. data/lib/switchman/active_record/base.rb +112 -22
  9. data/lib/switchman/active_record/calculations.rb +93 -37
  10. data/lib/switchman/active_record/connection_handler.rb +18 -0
  11. data/lib/switchman/active_record/connection_pool.rb +18 -14
  12. data/lib/switchman/active_record/database_configurations.rb +37 -15
  13. data/lib/switchman/active_record/finder_methods.rb +44 -14
  14. data/lib/switchman/active_record/log_subscriber.rb +11 -5
  15. data/lib/switchman/active_record/migration.rb +28 -9
  16. data/lib/switchman/active_record/pending_migration_connection.rb +17 -0
  17. data/lib/switchman/active_record/persistence.rb +22 -0
  18. data/lib/switchman/active_record/postgresql_adapter.rb +11 -10
  19. data/lib/switchman/active_record/predicate_builder.rb +2 -2
  20. data/lib/switchman/active_record/query_cache.rb +49 -20
  21. data/lib/switchman/active_record/query_methods.rb +93 -30
  22. data/lib/switchman/active_record/relation.rb +22 -11
  23. data/lib/switchman/active_record/spawn_methods.rb +2 -2
  24. data/lib/switchman/active_record/statement_cache.rb +2 -2
  25. data/lib/switchman/active_record/tasks/database_tasks.rb +6 -1
  26. data/lib/switchman/active_record/test_fixtures.rb +26 -16
  27. data/lib/switchman/active_support/cache.rb +9 -4
  28. data/lib/switchman/arel.rb +34 -18
  29. data/lib/switchman/call_super.rb +2 -8
  30. data/lib/switchman/database_server.rb +68 -21
  31. data/lib/switchman/default_shard.rb +14 -3
  32. data/lib/switchman/engine.rb +39 -19
  33. data/lib/switchman/environment.rb +2 -2
  34. data/lib/switchman/errors.rb +4 -1
  35. data/lib/switchman/guard_rail/relation.rb +1 -2
  36. data/lib/switchman/parallel.rb +5 -5
  37. data/lib/switchman/r_spec_helper.rb +11 -11
  38. data/lib/switchman/shard.rb +166 -64
  39. data/lib/switchman/sharded_instrumenter.rb +7 -3
  40. data/lib/switchman/standard_error.rb +4 -0
  41. data/lib/switchman/test_helper.rb +2 -2
  42. data/lib/switchman/version.rb +1 -1
  43. data/lib/switchman.rb +27 -15
  44. data/lib/tasks/switchman.rake +117 -51
  45. metadata +19 -44
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 28d87755bf2331cbbf2931e7d35dddd688983c168c583b27dd60ae58d78072db
4
- data.tar.gz: 500e141f914db02c5dd51cd9a595abc00306750a418641ceb09adb7cee207de7
3
+ metadata.gz: 2e86d08703a350aa5b8d3d843c51a0813f00e6ee0c681d0c95094f84863b327b
4
+ data.tar.gz: f13e438d68d996f55c9be543cc8cb89967b62f9ddd111ab4fae188da8b959096
5
5
  SHA512:
6
- metadata.gz: 94c9b870a65599c0d5775d32cd9dd1bfc3235c541eeb07127e5e8e8c773447da3ba1e0460ce8a340709354aceede546b9d6ccf8dd0360bff7e494f267a6791e1
7
- data.tar.gz: 6ea8348a8aaa9eb80ae763d2c8ccca23949e329f0f9ae2df7eef59344fdf3d4660b6e7419f479bc5d67be5e42fdd73f49abf7f0ceb853c0469c38b0899559424
6
+ metadata.gz: 7be63615d79be0b46184b9e6754bcb6091873e2eb0c4722705daea7dd81dd50320819b2238538c818637901570c2ad47a7ed62febd441c4d5b130c78391554cc
7
+ data.tar.gz: c3eb6290f9437ccac7162216840c2f258f31fc6c978121b9054c6308640bff6d522f2f61fd2247fea178c1c173a012a4d7f2c22b2e234d7b4f431ce4b8306403
data/Rakefile CHANGED
@@ -2,37 +2,38 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  begin
5
- require 'bundler/setup'
5
+ require "bundler/setup"
6
6
  rescue LoadError
7
- puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
+ puts "You must `gem install bundler` and `bundle install` to run rake tasks"
8
8
  end
9
9
  begin
10
- require 'rdoc/task'
10
+ require "rdoc/task"
11
11
  rescue LoadError
12
- require 'rdoc/rdoc'
13
- require 'rake/rdoctask'
12
+ require "rdoc/rdoc"
13
+ require "rake/rdoctask"
14
14
  RDoc::Task = Rake::RDocTask
15
15
  end
16
16
 
17
17
  RDoc::Task.new(:rdoc) do |rdoc|
18
- rdoc.rdoc_dir = 'rdoc'
19
- rdoc.title = 'Switchman'
20
- rdoc.options << '--line-numbers'
21
- rdoc.rdoc_files.include('lib/**/*.rb')
18
+ rdoc.rdoc_dir = "rdoc"
19
+ rdoc.title = "Switchman"
20
+ rdoc.options << "--line-numbers"
21
+ rdoc.rdoc_files.include("lib/**/*.rb")
22
22
  end
23
23
 
24
- APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
25
- load 'rails/tasks/engine.rake'
24
+ load "./spec/tasks/coverage.rake"
25
+ APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
26
+ load "rails/tasks/engine.rake"
26
27
 
27
28
  Bundler::GemHelper.install_tasks
28
29
 
29
- require 'rspec/core/rake_task'
30
+ require "rspec/core/rake_task"
30
31
  RSpec::Core::RakeTask.new
31
32
 
32
- require 'rubocop/rake_task'
33
+ require "rubocop/rake_task"
33
34
 
34
35
  RuboCop::RakeTask.new do |task|
35
- task.options = ['-S']
36
+ task.options = ["-S"]
36
37
  end
37
38
 
38
39
  task default: %i[spec]
@@ -5,7 +5,7 @@ class AddDefaultShardIndex < ActiveRecord::Migration[4.2]
5
5
  Switchman::Shard.where(default: nil).update_all(default: false) if Switchman::Shard.current.default?
6
6
  change_column_default :switchman_shards, :default, false
7
7
  change_column_null :switchman_shards, :default, false
8
- options = if connection.adapter_name == 'PostgreSQL'
8
+ options = if connection.adapter_name == "PostgreSQL"
9
9
  { unique: true, where: '"default"' }
10
10
  else
11
11
  {}
@@ -3,9 +3,15 @@
3
3
  class AddUniqueNameIndexes < ActiveRecord::Migration[4.2]
4
4
  def change
5
5
  add_index :switchman_shards, %i[database_server_id name], unique: true
6
- add_index :switchman_shards, :database_server_id, unique: true, where: 'name IS NULL',
7
- name: 'index_switchman_shards_unique_primary_shard'
8
- add_index :switchman_shards, '(true)', unique: true, where: 'database_server_id IS NULL AND name IS NULL',
9
- name: 'index_switchman_shards_unique_primary_db_and_shard'
6
+ add_index :switchman_shards,
7
+ :database_server_id,
8
+ unique: true,
9
+ where: "name IS NULL",
10
+ name: "index_switchman_shards_unique_primary_shard"
11
+ add_index :switchman_shards,
12
+ "(true)",
13
+ unique: true,
14
+ where: "database_server_id IS NULL AND name IS NULL",
15
+ name: "index_switchman_shards_unique_primary_db_and_shard"
10
16
  end
11
17
  end
@@ -27,8 +27,10 @@ module Switchman
27
27
  quote_table_name(name)
28
28
  end
29
29
 
30
- def schema_migration
31
- ::ActiveRecord::SchemaMigration
30
+ if ::Rails.version < "7.1"
31
+ def schema_migration
32
+ ::ActiveRecord::SchemaMigration
33
+ end
32
34
  end
33
35
 
34
36
  protected
@@ -24,11 +24,23 @@ module Switchman
24
24
 
25
25
  module CollectionAssociation
26
26
  def find_target
27
- shards = reflection.options[:multishard] && owner.respond_to?(:associated_shards) ? owner.associated_shards : [shard]
27
+ shards = if reflection.options[:multishard] && owner.respond_to?(:associated_shards)
28
+ owner.associated_shards
29
+ else
30
+ [shard]
31
+ end
28
32
  # activate both the owner and the target's shard category, so that Reflection#join_id_for,
29
33
  # when called for the owner, will be returned relative to shard the query will execute on
30
- Shard.with_each_shard(shards, [klass.connection_class_for_self, owner.class.connection_class_for_self].uniq) do
31
- super
34
+ Shard.with_each_shard(shards,
35
+ [klass.connection_class_for_self, owner.class.connection_class_for_self].uniq) do
36
+ if reflection.options[:multishard] && owner.respond_to?(:associated_shards) && reflection.has_scope?
37
+ # Prevent duplicate results when reflection has a scope (when it would use the skip_statement_cache? path)
38
+ # otherwise, the super call will set the shard_value to the object, causing it to iterate too many times
39
+ # over the associated shards
40
+ scope.shard(Shard.current(scope.klass.connection_class_for_self), :association).to_a
41
+ else
42
+ super
43
+ end
32
44
  end
33
45
  end
34
46
 
@@ -128,7 +140,12 @@ module Switchman
128
140
  Shard.lookup(shard).activate do
129
141
  scope_was = loader_query.scope
130
142
  begin
131
- loader_query.instance_variable_set(:@scope, loader_query.scope.shard(Shard.current(loader_query.scope.model.connection_class_for_self)))
143
+ loader_query.instance_variable_set(
144
+ :@scope,
145
+ loader_query.scope.shard(
146
+ Shard.current(loader_query.scope.model.connection_class_for_self)
147
+ )
148
+ )
132
149
  ret += loader_query.load_records_for_keys(keys) do |record|
133
150
  loaders.each { |l| l.set_inverse(record) }
134
151
  end
@@ -186,7 +203,7 @@ module Switchman
186
203
  # #compare_by_identity makes such owners different hash keys
187
204
  @records_by_owner = {}.compare_by_identity
188
205
 
189
- if ::Rails.version >= '7.0'
206
+ if ::Rails.version >= "7.0"
190
207
  raw_records ||= loader_query.records_for([self])
191
208
  elsif owner_keys.empty?
192
209
  raw_records ||= []
@@ -210,7 +227,8 @@ module Switchman
210
227
  relative_owner_keys = partitioned_owners.map do |owner|
211
228
  key = owner[owner_key_name]
212
229
  if key && owner.class.sharded_column?(owner_key_name)
213
- key = Shard.relative_id_for(key, owner.shard,
230
+ key = Shard.relative_id_for(key,
231
+ owner.shard,
214
232
  Shard.current(klass.connection_class_for_self))
215
233
  end
216
234
  convert_key(key)
@@ -273,18 +291,73 @@ module Switchman
273
291
  end
274
292
 
275
293
  module AutosaveAssociation
276
- def association_foreign_key_changed?(reflection, record, key)
277
- return false if reflection.through_reflection?
294
+ if ::Rails.version < "7.1"
295
+ def association_foreign_key_changed?(reflection, record, key)
296
+ return false if reflection.through_reflection?
278
297
 
279
- # have to use send instead of _read_attribute because sharding
280
- record.has_attribute?(reflection.foreign_key) && record.send(reflection.foreign_key) != key
281
- end
298
+ # have to use send instead of _read_attribute because sharding
299
+ record.has_attribute?(reflection.foreign_key) && record.send(reflection.foreign_key) != key
300
+ end
301
+
302
+ def save_belongs_to_association(reflection)
303
+ # this seems counter-intuitive, but the autosave code will assign to attribute bypassing switchman,
304
+ # after reading the id attribute _without_ bypassing switchman. So we need Shard.current for the
305
+ # category of the associated record to match Shard.current for the category of self
306
+ shard.activate(connection_class_for_self_for_reflection(reflection)) { super }
307
+ end
308
+ else
309
+ def association_foreign_key_changed?(reflection, record, key)
310
+ return false if reflection.through_reflection?
311
+
312
+ foreign_key = Array(reflection.foreign_key)
313
+ return false unless foreign_key.all? { |k| record._has_attribute?(k) }
314
+
315
+ # have to use send instead of _read_attribute because sharding
316
+ foreign_key.map { |k| record.send(k) } != Array(key)
317
+ end
282
318
 
283
- def save_belongs_to_association(reflection)
284
- # this seems counter-intuitive, but the autosave code will assign to attribute bypassing switchman,
285
- # after reading the id attribute _without_ bypassing switchman. So we need Shard.current for the
286
- # category of the associated record to match Shard.current for the category of self
287
- shard.activate(connection_class_for_self_for_reflection(reflection)) { super }
319
+ def save_belongs_to_association(reflection)
320
+ association = association_instance_get(reflection.name)
321
+ return unless association&.loaded? && !association.stale_target?
322
+
323
+ record = association.load_target
324
+ return unless record && !record.destroyed?
325
+
326
+ autosave = reflection.options[:autosave]
327
+
328
+ if autosave && record.marked_for_destruction?
329
+ foreign_key = Array(reflection.foreign_key)
330
+ foreign_key.each { |key| self[key] = nil }
331
+ record.destroy
332
+ elsif autosave != false
333
+ if record.new_record? || (autosave && record.changed_for_autosave?)
334
+ saved = record.save(validate: !autosave)
335
+ end
336
+
337
+ if association.updated?
338
+ primary_key = Array(compute_primary_key(reflection, record)).map(&:to_s)
339
+ foreign_key = Array(reflection.foreign_key)
340
+
341
+ primary_key_foreign_key_pairs = primary_key.zip(foreign_key)
342
+ primary_key_foreign_key_pairs.each do |pk, fk|
343
+ # Notable change: add relative_id_for here
344
+ association_id = if record.class.sharded_column?(pk)
345
+ Shard.relative_id_for(
346
+ record._read_attribute(pk),
347
+ record.shard,
348
+ shard
349
+ )
350
+ else
351
+ record._read_attribute(pk)
352
+ end
353
+ self[fk] = association_id unless self[fk] == association_id
354
+ end
355
+ association.loaded!
356
+ end
357
+
358
+ saved if autosave
359
+ end
360
+ end
288
361
  end
289
362
  end
290
363
  end
@@ -31,8 +31,16 @@ module Switchman
31
31
  # and not the silly one in AR::AttributeMethods::PrimaryKey
32
32
  return unless sharded_column?(@primary_key)
33
33
 
34
- class_eval(build_sharded_getter('id', '_read_attribute(@primary_key)', "::#{connection_class_for_self.name}"), __FILE__, __LINE__)
35
- class_eval(build_sharded_setter('id', @primary_key, "::#{connection_class_for_self.name}"), __FILE__, __LINE__)
34
+ class_eval(
35
+ build_sharded_getter("id",
36
+ "_read_attribute(@primary_key)",
37
+ "::#{connection_class_for_self.name}"),
38
+ __FILE__,
39
+ __LINE__
40
+ )
41
+ class_eval(build_sharded_setter("id", @primary_key, "::#{connection_class_for_self.name}"),
42
+ __FILE__,
43
+ __LINE__)
36
44
  end
37
45
 
38
46
  protected
@@ -47,7 +55,7 @@ module Switchman
47
55
  end
48
56
 
49
57
  def define_cached_method(owner, name, namespace:, as:, &block)
50
- if ::Rails.version < '7.0'
58
+ if ::Rails.version < "7.0"
51
59
  yield owner
52
60
  owner.rename_method(as, name)
53
61
  else
@@ -57,7 +65,10 @@ module Switchman
57
65
 
58
66
  def define_method_global_attribute(attr_name, owner:)
59
67
  if sharded_column?(attr_name)
60
- define_cached_method(owner, "global_#{attr_name}", as: "sharded_global_#{attr_name}", namespace: :switchman) do |batch|
68
+ define_cached_method(owner,
69
+ "global_#{attr_name}",
70
+ as: "sharded_global_#{attr_name}",
71
+ namespace: :switchman) do |batch|
61
72
  batch << <<-RUBY
62
73
  def sharded_global_#{attr_name}
63
74
  raw_value = original_#{attr_name}
@@ -69,13 +80,16 @@ module Switchman
69
80
  RUBY
70
81
  end
71
82
  else
72
- define_method_unsharded_column(attr_name, 'global', owner)
83
+ define_method_unsharded_column(attr_name, "global", owner)
73
84
  end
74
85
  end
75
86
 
76
87
  def define_method_local_attribute(attr_name, owner:)
77
88
  if sharded_column?(attr_name)
78
- define_cached_method(owner, "local_#{attr_name}", as: "sharded_local_#{attr_name}", namespace: :switchman) do |batch|
89
+ define_cached_method(owner,
90
+ "local_#{attr_name}",
91
+ as: "sharded_local_#{attr_name}",
92
+ namespace: :switchman) do |batch|
79
93
  batch << <<-RUBY
80
94
  def sharded_local_#{attr_name}
81
95
  raw_value = original_#{attr_name}
@@ -85,7 +99,7 @@ module Switchman
85
99
  RUBY
86
100
  end
87
101
  else
88
- define_method_unsharded_column(attr_name, 'local', owner)
102
+ define_method_unsharded_column(attr_name, "local", owner)
89
103
  end
90
104
  end
91
105
 
@@ -97,7 +111,13 @@ module Switchman
97
111
  if reflection.options[:polymorphic]
98
112
  # a polymorphic association has to be discovered at runtime. This code ends up being something like
99
113
  # context_type.&.constantize&.connection_class_for_self
100
- "begin;read_attribute(:#{reflection.foreign_type})&.constantize&.connection_class_for_self;rescue NameError;::ActiveRecord::Base;end"
114
+ <<~RUBY
115
+ begin
116
+ read_attribute(:#{reflection.foreign_type})&.constantize&.connection_class_for_self
117
+ rescue NameError
118
+ ::ActiveRecord::Base
119
+ end
120
+ RUBY
101
121
  else
102
122
  # otherwise we can just return a symbol for the statically known type of the association
103
123
  "::#{reflection.klass.connection_class_for_self.name}"
@@ -111,9 +131,14 @@ module Switchman
111
131
  if sharded_column?(attr_name)
112
132
  reflection = reflection_for_integer_attribute(attr_name)
113
133
  class_name = connection_class_for_self_code_for_reflection(reflection)
114
- safe_class_name = class_name.unpack1('h*')
115
- define_cached_method(owner, attr_name, as: "sharded_#{safe_class_name}_#{attr_name}", namespace: :switchman) do |batch|
116
- batch << build_sharded_getter("sharded_#{safe_class_name}_#{attr_name}", "original_#{attr_name}", class_name)
134
+ safe_class_name = class_name.unpack1("h*")
135
+ define_cached_method(owner,
136
+ attr_name,
137
+ as: "sharded_#{safe_class_name}_#{attr_name}",
138
+ namespace: :switchman) do |batch|
139
+ batch << build_sharded_getter("sharded_#{safe_class_name}_#{attr_name}",
140
+ "original_#{attr_name}",
141
+ class_name)
117
142
  end
118
143
  else
119
144
  define_cached_method(owner, attr_name, as: "plain_#{attr_name}", namespace: :switchman) do |batch|
@@ -153,8 +178,11 @@ module Switchman
153
178
  if sharded_column?(attr_name)
154
179
  reflection = reflection_for_integer_attribute(attr_name)
155
180
  class_name = connection_class_for_self_code_for_reflection(reflection)
156
- safe_class_name = class_name.unpack1('h*')
157
- define_cached_method(owner, "#{attr_name}=", as: "sharded_#{safe_class_name}_#{attr_name}=", namespace: :switchman) do |batch|
181
+ safe_class_name = class_name.unpack1("h*")
182
+ define_cached_method(owner,
183
+ "#{attr_name}=",
184
+ as: "sharded_#{safe_class_name}_#{attr_name}=",
185
+ namespace: :switchman) do |batch|
158
186
  batch << build_sharded_setter("sharded_#{safe_class_name}_#{attr_name}", attr_name, class_name)
159
187
  end
160
188
  else
@@ -178,7 +206,10 @@ module Switchman
178
206
 
179
207
  def define_method_original_attribute(attr_name, owner:)
180
208
  if sharded_column?(attr_name)
181
- define_cached_method(owner, "original_#{attr_name}", as: "sharded_original_#{attr_name}", namespace: :switchman) do |batch|
209
+ define_cached_method(owner,
210
+ "original_#{attr_name}",
211
+ as: "sharded_original_#{attr_name}",
212
+ namespace: :switchman) do |batch|
182
213
  batch << <<-RUBY
183
214
  def sharded_original_#{attr_name}
184
215
  _read_attribute("#{attr_name}") { |n| missing_attribute(n, caller) }
@@ -186,14 +217,17 @@ module Switchman
186
217
  RUBY
187
218
  end
188
219
  else
189
- define_method_unsharded_column(attr_name, 'global', owner)
220
+ define_method_unsharded_column(attr_name, "global", owner)
190
221
  end
191
222
  end
192
223
 
193
224
  def define_method_original_attribute=(attr_name, owner:)
194
225
  return unless sharded_column?(attr_name)
195
226
 
196
- define_cached_method(owner, "original_#{attr_name}=", as: "sharded_original_#{attr_name}=", namespace: :switchman) do |batch|
227
+ define_cached_method(owner,
228
+ "original_#{attr_name}=",
229
+ as: "sharded_original_#{attr_name}=",
230
+ namespace: :switchman) do |batch|
197
231
  batch << <<-RUBY
198
232
  def sharded_original_#{attr_name}=(new_value)
199
233
  _write_attribute('#{attr_name}', new_value)
@@ -203,9 +237,12 @@ module Switchman
203
237
  end
204
238
 
205
239
  def define_method_unsharded_column(attr_name, prefix, owner)
206
- return if columns_hash["#{prefix}_#{attr_name}"] || attr_name == 'id'
240
+ return if columns_hash["#{prefix}_#{attr_name}"] || attr_name == "id"
207
241
 
208
- define_cached_method(owner, "#{prefix}_#{attr_name}", as: "unsharded_#{prefix}_#{attr_name}", namespace: :switchman) do |batch|
242
+ define_cached_method(owner,
243
+ "#{prefix}_#{attr_name}",
244
+ as: "unsharded_#{prefix}_#{attr_name}",
245
+ namespace: :switchman) do |batch|
209
246
  batch << <<-RUBY
210
247
  def unsharded_#{prefix}_#{attr_name}
211
248
  raise NoMethodError, "undefined method `#{prefix}_#{attr_name}'; are you missing an association?"
@@ -217,8 +254,8 @@ module Switchman
217
254
 
218
255
  def self.prepended(klass)
219
256
  klass.singleton_class.prepend(ClassMethods)
220
- klass.attribute_method_prefix 'global_', 'local_', 'original_'
221
- klass.attribute_method_affix prefix: 'original_', suffix: '='
257
+ klass.attribute_method_prefix "global_", "local_", "original_"
258
+ klass.attribute_method_affix prefix: "original_", suffix: "="
222
259
  end
223
260
 
224
261
  # these are called if the specific methods haven't been defined yet
@@ -226,7 +263,11 @@ module Switchman
226
263
  return super unless self.class.sharded_column?(attr_name)
227
264
 
228
265
  reflection = self.class.send(:reflection_for_integer_attribute, attr_name)
229
- ::Switchman::Shard.relative_id_for(super, shard, ::Switchman::Shard.current(connection_class_for_self_for_reflection(reflection)))
266
+ ::Switchman::Shard.relative_id_for(
267
+ super,
268
+ shard,
269
+ ::Switchman::Shard.current(connection_class_for_self_for_reflection(reflection))
270
+ )
230
271
  end
231
272
 
232
273
  def attribute=(attr_name, new_value)
@@ -236,7 +277,11 @@ module Switchman
236
277
  end
237
278
 
238
279
  reflection = self.class.send(:reflection_for_integer_attribute, attr_name)
239
- super(::Switchman::Shard.relative_id_for(new_value, ::Switchman::Shard.current(connection_class_for_self_for_reflection(reflection)), shard))
280
+ super(attr_name, ::Switchman::Shard.relative_id_for(
281
+ new_value,
282
+ ::Switchman::Shard.current(connection_class_for_self_for_reflection(reflection)),
283
+ shard
284
+ ))
240
285
  end
241
286
 
242
287
  def global_attribute(attr_name)