Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
张重言
rails
提交
49fee3d2
R
rails
项目概览
张重言
/
rails
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
rails
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
49fee3d2
编写于
6月 14, 2014
作者:
M
Matthew Draper
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #15674 from sgrif/sg-mutable-attributes
Detect in-place changes on mutable AR attributes
上级
1dcb8e99
4bf8ffc6
变更
12
隐藏空白更改
内联
并排
Showing
12 changed file
with
149 addition
and
36 deletion
+149
-36
activerecord/CHANGELOG.md
activerecord/CHANGELOG.md
+6
-0
activerecord/lib/active_record/attribute_methods/dirty.rb
activerecord/lib/active_record/attribute_methods/dirty.rb
+77
-6
activerecord/lib/active_record/attribute_methods/serialization.rb
...cord/lib/active_record/attribute_methods/serialization.rb
+0
-17
activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb
...ctive_record/connection_adapters/postgresql/oid/hstore.rb
+2
-4
activerecord/lib/active_record/connection_adapters/postgresql/oid/json.rb
.../active_record/connection_adapters/postgresql/oid/json.rb
+2
-4
activerecord/lib/active_record/type.rb
activerecord/lib/active_record/type.rb
+1
-0
activerecord/lib/active_record/type/mutable.rb
activerecord/lib/active_record/type/mutable.rb
+16
-0
activerecord/lib/active_record/type/serialized.rb
activerecord/lib/active_record/type/serialized.rb
+2
-4
activerecord/lib/active_record/type/value.rb
activerecord/lib/active_record/type/value.rb
+4
-0
activerecord/test/cases/adapters/postgresql/hstore_test.rb
activerecord/test/cases/adapters/postgresql/hstore_test.rb
+9
-0
activerecord/test/cases/adapters/postgresql/json_test.rb
activerecord/test/cases/adapters/postgresql/json_test.rb
+20
-0
activerecord/test/cases/dirty_test.rb
activerecord/test/cases/dirty_test.rb
+10
-1
未找到文件。
activerecord/CHANGELOG.md
浏览文件 @
49fee3d2
*
`ActiveRecord::Dirty`
now detects in-place changes to mutable values.
Serialized attributes on ActiveRecord models will no longer save when
unchanged. Fixes #8328.
Sean Griffin
*
Fixed automatic maintaining test schema to properly handle sql structure
schema format.
...
...
activerecord/lib/active_record/attribute_methods/dirty.rb
浏览文件 @
49fee3d2
...
...
@@ -38,12 +38,39 @@ def reload(*)
end
end
def
initialize_dup
(
other
)
# :nodoc:
super
init_changed_attributes
end
def
initialize_dup
(
other
)
# :nodoc:
super
init_changed_attributes
end
def
changed?
super
||
changed_in_place
.
any?
end
def
changed
super
|
changed_in_place
end
def
attribute_changed?
(
attr_name
,
options
=
{})
result
=
super
# We can't change "from" something in place. Only setters can define
# "from" and "to"
result
||=
changed_in_place?
(
attr_name
)
unless
options
.
key?
(
:from
)
result
end
def
changes_applied
super
store_original_raw_attributes
end
def
reset_changes
super
original_raw_attributes
.
clear
end
private
private
def
initialize_internals_callback
super
init_changed_attributes
...
...
@@ -65,11 +92,20 @@ def write_attribute(attr, value)
old_value
=
old_attribute_value
(
attr
)
result
=
super
(
attr
,
value
)
result
=
super
store_original_raw_attribute
(
attr
)
save_changed_attribute
(
attr
,
old_value
)
result
end
def
raw_write_attribute
(
attr
,
value
)
attr
=
attr
.
to_s
result
=
super
original_raw_attributes
[
attr
]
=
value
result
end
def
save_changed_attribute
(
attr
,
old_value
)
if
attribute_changed?
(
attr
)
changed_attributes
.
delete
(
attr
)
unless
_field_changed?
(
attr
,
old_value
)
...
...
@@ -105,6 +141,41 @@ def _field_changed?(attr, old_value)
raw_value
=
read_attribute_before_type_cast
(
attr
)
column_for_attribute
(
attr
).
changed?
(
old_value
,
new_value
,
raw_value
)
end
def
changed_in_place
self
.
class
.
attribute_names
.
select
do
|
attr_name
|
changed_in_place?
(
attr_name
)
end
end
def
changed_in_place?
(
attr_name
)
type
=
type_for_attribute
(
attr_name
)
old_value
=
original_raw_attribute
(
attr_name
)
value
=
read_attribute
(
attr_name
)
type
.
changed_in_place?
(
old_value
,
value
)
end
def
original_raw_attribute
(
attr_name
)
original_raw_attributes
.
fetch
(
attr_name
)
do
read_attribute_before_type_cast
(
attr_name
)
end
end
def
original_raw_attributes
@original_raw_attributes
||=
{}
end
def
store_original_raw_attribute
(
attr_name
)
type
=
type_for_attribute
(
attr_name
)
value
=
type
.
type_cast_for_database
(
read_attribute
(
attr_name
))
original_raw_attributes
[
attr_name
]
=
value
end
def
store_original_raw_attributes
attribute_names
.
each
do
|
attr
|
store_original_raw_attribute
(
attr
)
end
end
end
end
end
activerecord/lib/active_record/attribute_methods/serialization.rb
浏览文件 @
49fee3d2
...
...
@@ -50,8 +50,6 @@ module ClassMethods
# serialize :preferences, Hash
# end
def
serialize
(
attr_name
,
class_name_or_coder
=
Object
)
include
Behavior
coder
=
if
[
:load
,
:dump
].
all?
{
|
x
|
class_name_or_coder
.
respond_to?
(
x
)
}
class_name_or_coder
else
...
...
@@ -67,21 +65,6 @@ def serialize(attr_name, class_name_or_coder = Object)
self
.
serialized_attributes
=
serialized_attributes
.
merge
(
attr_name
.
to_s
=>
coder
)
end
end
# This is only added to the model when serialize is called, which
# ensures we do not make things slower when serialization is not used.
module
Behavior
# :nodoc:
extend
ActiveSupport
::
Concern
def
should_record_timestamps?
super
||
(
self
.
record_timestamps
&&
(
attributes
.
keys
&
self
.
class
.
serialized_attributes
.
keys
).
present?
)
end
def
keys_for_partial_write
super
|
(
attributes
.
keys
&
self
.
class
.
serialized_attributes
.
keys
)
end
end
end
end
end
activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb
浏览文件 @
49fee3d2
...
...
@@ -3,14 +3,12 @@ module ConnectionAdapters
module
PostgreSQL
module
OID
# :nodoc:
class
Hstore
<
Type
::
Value
include
Type
::
Mutable
def
type
:hstore
end
def
type_cast_from_user
(
value
)
type_cast_from_database
(
type_cast_for_database
(
value
))
end
def
type_cast_from_database
(
value
)
ConnectionAdapters
::
PostgreSQLColumn
.
string_to_hstore
(
value
)
end
...
...
activerecord/lib/active_record/connection_adapters/postgresql/oid/json.rb
浏览文件 @
49fee3d2
...
...
@@ -3,14 +3,12 @@ module ConnectionAdapters
module
PostgreSQL
module
OID
# :nodoc:
class
Json
<
Type
::
Value
include
Type
::
Mutable
def
type
:json
end
def
type_cast_from_user
(
value
)
type_cast_from_database
(
type_cast_for_database
(
value
))
end
def
type_cast_from_database
(
value
)
ConnectionAdapters
::
PostgreSQLColumn
.
string_to_json
(
value
)
end
...
...
activerecord/lib/active_record/type.rb
浏览文件 @
49fee3d2
require
'active_record/type/mutable'
require
'active_record/type/numeric'
require
'active_record/type/time_value'
require
'active_record/type/value'
...
...
activerecord/lib/active_record/type/mutable.rb
0 → 100644
浏览文件 @
49fee3d2
module
ActiveRecord
module
Type
module
Mutable
def
type_cast_from_user
(
value
)
type_cast_from_database
(
type_cast_for_database
(
value
))
end
# +raw_old_value+ will be the `_before_type_cast` version of the
# value (likely a string). +new_value+ will be the current, type
# cast value.
def
changed_in_place?
(
raw_old_value
,
new_value
)
# :nodoc:
raw_old_value
!=
type_cast_for_database
(
new_value
)
end
end
end
end
activerecord/lib/active_record/type/serialized.rb
浏览文件 @
49fee3d2
module
ActiveRecord
module
Type
class
Serialized
<
SimpleDelegator
# :nodoc:
include
Mutable
attr_reader
:subtype
,
:coder
def
initialize
(
subtype
,
coder
)
...
...
@@ -17,10 +19,6 @@ def type_cast_from_database(value)
end
end
def
type_cast_from_user
(
value
)
type_cast_from_database
(
type_cast_for_database
(
value
))
end
def
type_cast_for_database
(
value
)
return
if
value
.
nil?
unless
is_default_value?
(
value
)
...
...
activerecord/lib/active_record/type/value.rb
浏览文件 @
49fee3d2
...
...
@@ -60,6 +60,10 @@ def changed?(old_value, new_value, _new_value_before_type_cast) # :nodoc:
old_value
!=
new_value
end
def
changed_in_place?
(
*
)
# :nodoc:
false
end
private
# Takes an input from the database, or from attribute setters,
# and casts it to a type appropriate for this object. This method
...
...
activerecord/test/cases/adapters/postgresql/hstore_test.rb
浏览文件 @
49fee3d2
...
...
@@ -163,6 +163,15 @@ def test_yaml_round_trip_with_store_accessors
assert_equal
"GMT"
,
y
.
timezone
end
def
test_changes_in_place
hstore
=
Hstore
.
create!
(
settings:
{
'one'
=>
'two'
})
hstore
.
settings
[
'three'
]
=
'four'
hstore
.
save!
hstore
.
reload
assert_equal
'four'
,
hstore
.
settings
[
'three'
]
end
def
test_gen1
assert_equal
(
%q(" "=>"")
,
@column
.
class
.
hstore_to_string
({
' '
=>
''
}))
end
...
...
activerecord/test/cases/adapters/postgresql/json_test.rb
浏览文件 @
49fee3d2
...
...
@@ -165,4 +165,24 @@ def test_update_all
JsonDataType
.
update_all
payload:
{
}
assert_equal
({
},
json
.
reload
.
payload
)
end
def
test_changes_in_place
json
=
JsonDataType
.
new
assert_not
json
.
changed?
json
.
payload
=
{
'one'
=>
'two'
}
assert
json
.
changed?
assert
json
.
payload_changed?
json
.
save!
assert_not
json
.
changed?
json
.
payload
[
'three'
]
=
'four'
assert
json
.
payload_changed?
json
.
save!
json
.
reload
assert
json
.
payload
[
'three'
]
=
'four'
end
end
activerecord/test/cases/dirty_test.rb
浏览文件 @
49fee3d2
...
...
@@ -445,11 +445,20 @@ def test_reverted_changes_are_not_dirty_going_from_nil_to_value_and_back
def
test_save_should_store_serialized_attributes_even_with_partial_writes
with_partial_writes
(
Topic
)
do
topic
=
Topic
.
create!
(
:content
=>
{
:a
=>
"a"
})
assert_not
topic
.
changed?
topic
.
content
[
:b
]
=
"b"
#assert topic.changed? # Known bug, will fail
assert
topic
.
changed?
topic
.
save!
assert_not
topic
.
changed?
assert_equal
"b"
,
topic
.
content
[
:b
]
topic
.
reload
assert_equal
"b"
,
topic
.
content
[
:b
]
end
end
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录