public
Description: Ruby on Rails
Homepage: http://rubyonrails.org
Clone URL: git://github.com/rails/rails.git
Search Repo:
Dirty typecasts attribute values before comparison, if possible. Closes 
#11464 [Russell Norris, mroch]


git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@9139 
5ecf4fe2-1ee6-0310-87b1-e25e094e27de
jeremy (author)
Sat Mar 29 15:19:26 -0700 2008
commit  81286f858770e0b95e15af37f19156b044ec6a95
tree    752aaac65d38f75216b74cfb78492af1fd52a476
parent  eece9b4e8a9b46a909af424538c4cc55d78b0142
...
91
92
93
94
 
 
 
 
 
 
95
96
97
...
91
92
93
 
94
95
96
97
98
99
100
101
102
0
@@ -91,7 +91,12 @@ module ActiveRecord
0
           old = read_attribute(attr)
0
 
0
           # Remember the original value if it's different.
0
- changed_attributes[attr] = old unless old == value
0
+ typecasted = if column = column_for_attribute(attr)
0
+ column.type_cast(value)
0
+ else
0
+ value
0
+ end
0
+ changed_attributes[attr] = old unless old == typecasted
0
         end
0
 
0
         # Carry on.
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
34
35
36
37
38
39
40
41
42
43
44
 
 
 
45
46
47
48
49
50
 
 
 
 
 
51
52
53
54
55
 
 
 
56
57
58
59
60
 
 
 
61
62
 
63
64
65
66
67
68
69
70
71
72
73
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
75
76
77
78
 
 
 
 
 
 
 
 
 
 
 
79
80
...
1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
 
 
 
22
23
24
 
 
 
25
26
27
28
 
 
 
 
 
29
30
31
32
33
34
35
 
 
 
36
37
38
39
40
 
 
 
41
42
43
44
45
46
47
 
 
 
 
 
 
 
 
 
 
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
 
 
 
 
65
66
67
68
69
70
71
72
73
74
75
76
77
0
@@ -1,80 +1,77 @@
0
 require 'cases/helper'
0
-
0
-# Stub out an AR-alike.
0
-class DirtyTestSubject
0
- def self.table_name; 'people' end
0
- def self.primary_key; 'id' end
0
- def self.attribute_method_suffix(*suffixes) suffixes end
0
-
0
- def initialize(attrs = {}) @attributes = attrs end
0
-
0
- def save
0
- changed_attributes.clear
0
- end
0
-
0
- alias_method :save!, :save
0
-
0
- def name; read_attribute('name') end
0
- def name=(value); write_attribute('name', value) end
0
- def name_was; attribute_was('name') end
0
- def name_change; attribute_change('name') end
0
- def name_changed?; attribute_changed?('name') end
0
-
0
- private
0
- def define_read_methods; nil end
0
-
0
- def read_attribute(attr)
0
- @attributes[attr]
0
- end
0
-
0
- def write_attribute(attr, value)
0
- @attributes[attr] = value
0
+require 'models/topic' # For booleans
0
+require 'models/pirate' # For timestamps
0
+
0
+class Pirate # Just reopening it, not defining it
0
+ attr_accessor :detected_changes_in_after_update # Boolean for if changes are detected
0
+ attr_accessor :changes_detected_in_after_update # Actual changes
0
+
0
+ after_update :check_changes
0
+
0
+private
0
+ # after_save/update in sweepers, observers, and the model itself
0
+ # can end up checking dirty status and acting on the results
0
+ def check_changes
0
+ if self.changed?
0
+ self.detected_changes_in_after_update = true
0
+ self.changes_detected_in_after_update = self.changes
0
     end
0
+ end
0
 end
0
 
0
-# Include the module after the class is all set up.
0
-DirtyTestSubject.module_eval { include ActiveRecord::Dirty }
0
-
0
-
0
 class DirtyTest < Test::Unit::TestCase
0
   def test_attribute_changes
0
     # New record - no changes.
0
- person = DirtyTestSubject.new
0
- assert !person.name_changed?
0
- assert_nil person.name_change
0
+ pirate = Pirate.new
0
+ assert !pirate.catchphrase_changed?
0
+ assert_nil pirate.catchphrase_change
0
 
0
- # Change name.
0
- person.name = 'a'
0
- assert person.name_changed?
0
- assert_nil person.name_was
0
- assert_equal [nil, 'a'], person.name_change
0
+ # Change catchphrase.
0
+ pirate.catchphrase = 'arrr'
0
+ assert pirate.catchphrase_changed?
0
+ assert_nil pirate.catchphrase_was
0
+ assert_equal [nil, 'arrr'], pirate.catchphrase_change
0
 
0
     # Saved - no changes.
0
- person.save!
0
- assert !person.name_changed?
0
- assert_nil person.name_change
0
+ pirate.save!
0
+ assert !pirate.catchphrase_changed?
0
+ assert_nil pirate.catchphrase_change
0
 
0
     # Same value - no changes.
0
- person.name = 'a'
0
- assert !person.name_changed?
0
- assert_nil person.name_change
0
+ pirate.catchphrase = 'arrr'
0
+ assert !pirate.catchphrase_changed?
0
+ assert_nil pirate.catchphrase_change
0
   end
0
 
0
+ # Rewritten from original tests to use AR
0
   def test_object_should_be_changed_if_any_attribute_is_changed
0
- person = DirtyTestSubject.new
0
- assert !person.changed?
0
- assert_equal [], person.changed
0
- assert_equal Hash.new, person.changes
0
-
0
- person.name = 'a'
0
- assert person.changed?
0
- assert_nil person.name_was
0
- assert_equal %w(name), person.changed
0
- assert_equal({'name' => [nil, 'a']}, person.changes)
0
+ pirate = Pirate.new
0
+ assert !pirate.changed?
0
+ assert_equal [], pirate.changed
0
+ assert_equal Hash.new, pirate.changes
0
+
0
+ pirate.catchphrase = 'arrr'
0
+ assert pirate.changed?
0
+ assert_nil pirate.catchphrase_was
0
+ assert_equal %w(catchphrase), pirate.changed
0
+ assert_equal({'catchphrase' => [nil, 'arrr']}, pirate.changes)
0
+
0
+ pirate.save
0
+ assert !pirate.changed?
0
+ assert_equal [], pirate.changed
0
+ assert_equal Hash.new, pirate.changes
0
+ end
0
 
0
- person.save
0
- assert !person.changed?
0
- assert_equal [], person.changed
0
- assert_equal({}, person.changes)
0
+ def test_attribute_should_be_compared_with_type_cast
0
+ topic = Topic.new
0
+ assert topic.approved?
0
+ assert !topic.approved_changed?
0
+
0
+ # Coming from web form.
0
+ params = {:topic => {:approved => 1}}
0
+ # In the controller.
0
+ topic.attributes = params[:topic]
0
+ assert topic.approved?
0
+ assert !topic.approved_changed?
0
   end
0
 end

Comments

    No one has commented yet.