Skip to content

Commit 750fef5

Browse files
committed
Prevent infinite loops on attribute getter/setter overrides that are mutable.
1 parent bf00cc9 commit 750fef5

File tree

3 files changed

+37
-0
lines changed

3 files changed

+37
-0
lines changed

lib/mongoid/dirty.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,5 +108,22 @@ def attribute_changed?(attr)
108108
return false unless changed_attributes.include?(attr)
109109
changed_attributes[attr] != attributes[attr]
110110
end
111+
112+
# Override Active Model's behaviour here in order to stay away from
113+
# infinite loops on getter/setter overrides.
114+
#
115+
# @example Flag an attribute as changing.
116+
# document.attribute_will_change!(:name)
117+
#
118+
# @param [ Symbol ] attr The attribute.
119+
#
120+
# @return [ Object ] The value of the attribute.
121+
#
122+
# @since 2.3.0
123+
def attribute_will_change!(attr)
124+
value = read_attribute(attr)
125+
value = value.duplicable? ? value.clone : value
126+
changed_attributes[attr] = value unless changed_attributes.include?(attr)
127+
end
111128
end
112129
end

spec/app/models/account.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ class Account
44
field :balance, :type => String
55
field :nickname, :type => String
66
field :name, :type => String
7+
8+
field :overridden, :type => String
79
key :name
810

911
embeds_many :memberships
@@ -17,4 +19,8 @@ class Account
1719

1820
validates_presence_of :name
1921
validates_length_of :name, :maximum => 10, :on => :create
22+
23+
def overridden
24+
self[:overridden] = "not recommended"
25+
end
2026
end

spec/unit/mongoid/attributes_spec.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,20 @@
22

33
describe Mongoid::Attributes do
44

5+
describe "\#{attribute}" do
6+
7+
context "when setting the value in the getter" do
8+
9+
let(:account) do
10+
Account.new
11+
end
12+
13+
it "does not cause an infinite loop" do
14+
account.overridden.should eq("not recommended")
15+
end
16+
end
17+
end
18+
519
describe "#[]" do
620

721
context "when the document is a new record" do

0 commit comments

Comments
 (0)