Skip to content

Commit 97397b0

Browse files
neilshwekyp-mongo
andauthored
MONGOID-4403 Support Dirty Tracking changed from/to (#5432)
* MONGOID-4403 Support Dirty Tracking changed from/to * Apply suggestions from code review Co-authored-by: Oleg Pudeyev <39304720+p-mongo@users.noreply.github.com> * MONGOID-4403 add false example Co-authored-by: Oleg Pudeyev <39304720+p-mongo@users.noreply.github.com>
1 parent 49ff14f commit 97397b0

File tree

3 files changed

+227
-4
lines changed

3 files changed

+227
-4
lines changed

docs/release-notes/mongoid-8.1.txt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,32 @@ from the ``_translations`` hash:
116116

117117
See the section on :ref:`Localize :present Field Option <present-fields>` for
118118
more details on how these are used.
119+
120+
121+
Added ``:to`` and ``:from`` options to ``attribute_changed?``
122+
-------------------------------------------------------------
123+
124+
Mongoid 8.1 adds the ``:to`` and ``:from`` options on the ``attribute_changed?``
125+
method. These options can be used to inquire whether the attribute has been changed
126+
to or from a certain value:
127+
128+
.. code:
129+
130+
class Person
131+
include Mongoid::Document
132+
field :name, type: String
133+
end
134+
135+
person = Person.create!(name: "Trout")
136+
person.name = "Ohtani"
137+
138+
person.name_changed?
139+
# => true
140+
person.name_changed?(from: "Trout")
141+
# => true
142+
person.name_changed?(to: "Ohtani")
143+
# => true
144+
person.name_changed?(from: "Trout", to: "Ohtani")
145+
# => true
146+
person.name_changed?(from: "Trout", to: "Fletcher")
147+
# => false

lib/mongoid/changeable.rb

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,24 @@ def attribute_change(attr)
161161
# model.attribute_changed?("name")
162162
#
163163
# @param [ String ] attr The name of the attribute.
164+
# @param **kwargs The optional keyword arguments.
165+
#
166+
# @option **kwargs [ Object ] :from The object the attribute was changed from.
167+
# @option **kwargs [ Object ] :to The object the attribute was changed to.
164168
#
165169
# @return [ true | false ] Whether the attribute has changed.
166-
def attribute_changed?(attr)
170+
def attribute_changed?(attr, **kwargs)
167171
attr = database_field_name(attr)
168172
return false unless changed_attributes.key?(attr)
169-
changed_attributes[attr] != attributes[attr]
173+
return false if changed_attributes[attr] == attributes[attr]
174+
if kwargs.key?(:from)
175+
return false if changed_attributes[attr] != kwargs[:from]
176+
end
177+
if kwargs.key?(:to)
178+
return false if attributes[attr] != kwargs[:to]
179+
end
180+
181+
true
170182
end
171183

172184
# Get whether or not the field has a different value from the default.
@@ -302,8 +314,8 @@ def create_dirty_change_accessor(name, meth)
302314
# @param [ String ] meth The name of the accessor.
303315
def create_dirty_change_check(name, meth)
304316
generated_methods.module_eval do
305-
re_define_method("#{meth}_changed?") do
306-
attribute_changed?(name)
317+
re_define_method("#{meth}_changed?") do |**kwargs|
318+
attribute_changed?(name, **kwargs)
307319
end
308320
end
309321
end

spec/mongoid/changeable_spec.rb

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,188 @@
476476
end
477477
end
478478
end
479+
480+
context "when including key word args" do
481+
482+
let(:person) { Person.new }
483+
484+
context "when only including from" do
485+
486+
context "when the object has not changed" do
487+
488+
it "returns false" do
489+
expect(person.send(:attribute_changed?, :score, from: nil)).to be false
490+
end
491+
492+
it "returns false using (attribute)_changed?" do
493+
expect(person.score_changed?(from: nil)).to be false
494+
end
495+
end
496+
497+
context "when the object has changed from the wrong item" do
498+
499+
before do
500+
person.score = 2
501+
end
502+
503+
it "returns false" do
504+
expect(person.send(:attribute_changed?, :score, from: 1)).to be false
505+
end
506+
507+
it "returns false using (attribute)_changed?" do
508+
expect(person.score_changed?(from: 1)).to be false
509+
end
510+
end
511+
512+
context "when the object has changed from the correct item" do
513+
514+
before do
515+
person.score = 2
516+
end
517+
518+
it "returns true" do
519+
expect(person.send(:attribute_changed?, :score, from: nil)).to be true
520+
end
521+
522+
it "returns true using (attribute)_changed?" do
523+
expect(person.score_changed?(from: nil)).to be true
524+
end
525+
end
526+
end
527+
528+
context "when only including to" do
529+
530+
context "when the object has not changed" do
531+
532+
it "returns false" do
533+
expect(person.send(:attribute_changed?, :score, to: nil)).to be false
534+
end
535+
536+
it "returns false using (attribute)_changed?" do
537+
expect(person.score_changed?(to: nil)).to be false
538+
end
539+
end
540+
541+
context "when the object has changed to the wrong item" do
542+
543+
before do
544+
person.score = 2
545+
end
546+
547+
it "returns false" do
548+
expect(person.send(:attribute_changed?, :score, to: 1)).to be false
549+
end
550+
551+
it "returns false using (attribute)_changed?" do
552+
expect(person.score_changed?(to: 1)).to be false
553+
end
554+
end
555+
556+
context "when the object has changed to the correct item" do
557+
558+
before do
559+
person.score = 2
560+
end
561+
562+
it "returns true" do
563+
expect(person.send(:attribute_changed?, :score, to: 2)).to be true
564+
end
565+
566+
it "returns true using (attribute)_changed?" do
567+
expect(person.score_changed?(to: 2)).to be true
568+
end
569+
end
570+
end
571+
572+
context "when including from and to" do
573+
574+
context "when the object has not changed" do
575+
576+
it "returns false" do
577+
expect(person.send(:attribute_changed?, :score, from: nil, to: nil)).to be false
578+
end
579+
580+
it "returns false using (attribute)_changed?" do
581+
expect(person.score_changed?(from: nil, to: nil)).to be false
582+
end
583+
end
584+
585+
context "when only the from is correct" do
586+
587+
before do
588+
person.score = 2
589+
end
590+
591+
it "returns false" do
592+
expect(person.send(:attribute_changed?, :score, from: nil, to: 3)).to be false
593+
end
594+
595+
it "returns false using (attribute)_changed?" do
596+
expect(person.score_changed?(from: nil, to: 3)).to be false
597+
end
598+
end
599+
600+
context "when only the to is correct" do
601+
602+
before do
603+
person.score = 2
604+
end
605+
606+
it "returns false" do
607+
expect(person.send(:attribute_changed?, :score, from: 1, to: 2)).to be false
608+
end
609+
610+
it "returns false using (attribute)_changed?" do
611+
expect(person.score_changed?(from: 1, to: 2)).to be false
612+
end
613+
end
614+
615+
context "when the from and to are correct" do
616+
617+
before do
618+
person.score = 2
619+
end
620+
621+
it "returns true" do
622+
expect(person.send(:attribute_changed?, :score, from: nil, to: 2)).to be true
623+
end
624+
625+
it "returns true using (attribute)_changed?" do
626+
expect(person.score_changed?(from: nil, to: 2)).to be true
627+
end
628+
end
629+
630+
context "when value is mongoized" do
631+
632+
before do
633+
person.score = "2"
634+
end
635+
636+
it "returns true with mongoized value" do
637+
expect(person.send(:attribute_changed?, :score, from: nil, to: 2)).to be true
638+
end
639+
640+
it "returns true with mongoized value using (attribute)_changed?" do
641+
expect(person.score_changed?(from: nil, to: 2)).to be true
642+
end
643+
end
644+
645+
context "when value is mongoized" do
646+
647+
before do
648+
person.score = "2"
649+
end
650+
651+
it "returns false with unmongoized value" do
652+
expect(person.send(:attribute_changed?, :score, from: nil, to: "2")).to be false
653+
end
654+
655+
it "returns false with unmongoized value using (attribute)_changed?" do
656+
expect(person.score_changed?(from: nil, to: "2")).to be false
657+
end
658+
end
659+
end
660+
end
479661
end
480662

481663
describe "#attribute_changed_from_default?" do

0 commit comments

Comments
 (0)