Skip to content
This repository was archived by the owner on Apr 22, 2025. It is now read-only.

Commit bc68e50

Browse files
committed
It was possible to modify a models id and the instance still retain the memoized encoded_id, this change is meant to make this more robust
1 parent a5f0b14 commit bc68e50

File tree

1 file changed

+36
-7
lines changed

1 file changed

+36
-7
lines changed

lib/encoded_id/rails/model.rb

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,31 +17,61 @@ def self.included(base)
1717
end
1818
end
1919

20+
attr_accessor :encoded_id_memoized_with_id
21+
22+
def clear_encoded_id_cache!
23+
[:@encoded_id_hash, :@encoded_id, :@slugged_encoded_id].each do |var|
24+
remove_instance_variable(var) if instance_variable_defined?(var)
25+
end
26+
self.encoded_id_memoized_with_id = nil
27+
end
28+
29+
def check_and_clear_memoization
30+
clear_encoded_id_cache! if encoded_id_memoized_with_id && encoded_id_memoized_with_id != id
31+
end
32+
2033
def encoded_id_hash
2134
return unless id
22-
return @encoded_id_hash if defined?(@encoded_id_hash) && !id_changed?
23-
self.class.encode_encoded_id(id)
35+
check_and_clear_memoization
36+
return @encoded_id_hash if defined?(@encoded_id_hash)
37+
38+
self.encoded_id_memoized_with_id = id
39+
@encoded_id_hash = self.class.encode_encoded_id(id)
2440
end
2541

2642
def encoded_id
2743
return unless id
28-
return @encoded_id if defined?(@encoded_id) && !id_changed?
44+
check_and_clear_memoization
45+
return @encoded_id if defined?(@encoded_id)
46+
2947
encoded = encoded_id_hash
3048
annotated_by = EncodedId::Rails.configuration.annotation_method_name
3149
return @encoded_id = encoded unless annotated_by && encoded
50+
3251
separator = EncodedId::Rails.configuration.annotated_id_separator
52+
self.encoded_id_memoized_with_id = id
3353
@encoded_id = EncodedId::Rails::AnnotatedId.new(id_part: encoded, annotation: send(annotated_by.to_s), separator: separator).annotated_id
3454
end
3555

3656
def slugged_encoded_id
3757
return unless id
38-
return @slugged_encoded_id if defined?(@slugged_encoded_id) && !id_changed?
58+
check_and_clear_memoization
59+
return @slugged_encoded_id if defined?(@slugged_encoded_id)
60+
3961
with = EncodedId::Rails.configuration.slug_value_method_name
4062
separator = EncodedId::Rails.configuration.slugged_id_separator
4163
encoded = encoded_id
4264
return unless encoded
65+
66+
self.encoded_id_memoized_with_id = id
4367
@slugged_encoded_id = EncodedId::Rails::SluggedId.new(id_part: encoded, slug_part: send(with.to_s), separator: separator).slugged_id
4468
end
69+
70+
def reload(options = nil)
71+
result = super
72+
clear_encoded_id_cache!
73+
result
74+
end
4575

4676
# By default the annotation is the model name (it will be parameterized)
4777
def annotation_for_encoded_id
@@ -57,11 +87,10 @@ def name_for_encoded_id_slug
5787
raise StandardError, "You must define a method to generate the slug for the encoded ID of #{self.class.name}"
5888
end
5989

60-
# When duplicating an ActiveRecord object, we want to reset the memoized encoded_id
90+
# When duplicating an ActiveRecord object, we want to reset the memoized encoded IDs
6191
def dup
6292
super.tap do |new_record|
63-
new_record.send(:remove_instance_variable, :@encoded_id) if new_record.instance_variable_defined?(:@encoded_id)
64-
new_record.send(:remove_instance_variable, :@slugged_encoded_id) if new_record.instance_variable_defined?(:@slugged_encoded_id)
93+
new_record.clear_encoded_id_cache!
6594
end
6695
end
6796
end

0 commit comments

Comments
 (0)