hsi*_*dar 6 ruby arrays serialization ruby-on-rails
在Ruby on Rails中,.save()如果数组是空的,那么带有序列化数组字段的模型将不会更新,之前它有数据.
我正在使用:
sqlite3 1.3.10
我创建了一个新的模型,其字段设置为文本:
rails g model用户名:string example:text
在User.rb文件中,我添加了:
serialize :example, Array
Run Code Online (Sandbox Code Playgroud)
我实例化了User类的新实例:
test = User.new
<User id: nil, name: nil, example: [], created_at: nil, updated_at: nil>
Run Code Online (Sandbox Code Playgroud)
然后我保存用户以确保它正确保存:
test.save()
(0.1ms) begin transaction
SQL (0.4ms) INSERT INTO "users" ("created_at", "updated_at") VALUES (?, ?) [["created_at", "2015-05-27 16:17:31.902342"], ["updated_at", "2015-05-27 16:17:31.902342"]]
(0.7ms) commit transaction
=> true
Run Code Online (Sandbox Code Playgroud)
并添加了一些数据,以使其感到愉快和有目的:
test.example.push(1)
test.example.push(2)
Run Code Online (Sandbox Code Playgroud)
并保存起来:
test.save()
(0.1ms) begin transaction
SQL (0.3ms) UPDATE "users" SET "example" = ?, "updated_at" = ? WHERE "users"."id" = ? [["example", "---\n- 1\n- 2\n"], ["updated_at", "2015-05-27 16:17:50.331777"], ["id", 1]]
(0.8ms) commit transaction
=> true
Run Code Online (Sandbox Code Playgroud)
并确保一切都很好地保存:
test
<User id: 1, name: nil, example: [1, 2], created_at: "2015-05-27 16:17:31", updated_at: "2015-05-27 16:17:50">
Run Code Online (Sandbox Code Playgroud)
我删除了一个项目,验证它已被删除并保存,确保SQL输出显示UPDATE:
test.example.delete(1)
=> 1
test
<User id: 1, name: nil, example: [2], created_at: "2015-05-27 16:17:31", updated_at: "2015-05-27 16:17:50">
test.save()
(0.1ms) begin transaction
SQL (0.9ms) UPDATE "users" SET "example" = ?, "updated_at" = ? WHERE "users"."id" = ? [["example", "---\n- 2\n"], ["updated_at", "2015-05-27 16:18:30.148553"], ["id", 1]]
(8.9ms) commit transaction
=> true
Run Code Online (Sandbox Code Playgroud)
我从数组中删除了最后一段数据,验证了空数组并保存了它.请注意缺少UPDATE操作并返回true:
test.example.delete(2)
=> 2
test
<User id: 1, name: nil, example: [], created_at: "2015-05-27 16:17:31", updated_at: "2015-05-27 16:18:30">
test.save()
(0.1ms) begin transaction
(0.1ms) commit transaction
=> true
Run Code Online (Sandbox Code Playgroud)
多次保存可获得相同的结果.新的User对象仍然包含最后一段数据:
test = User.find(1)
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", 1]]
<User id: 1, name: nil, example: [2], created_at: "2015-05-27 16:17:31", updated_at: "2015-05-27 16:18:30">
Run Code Online (Sandbox Code Playgroud)
解决方法是从模型中的序列化行中删除"数组",将字段初始化为nil.但这意味着我第一次将数据添加到新实例时,我必须手动将字段设置为空数组(test.example = [])以便调用.push()它.在这个设置中一切正常,新清空的数组可以很好地保存到数据库中.
我在Rails Github上看到一个封闭的问题,表明应该始终保存序列化列,但不知道这是否相关:
https://github.com/rails/rails/issues/8328
我无法从可能照亮我的序列化源代码中辨别出任何内容:
http://apidock.com/rails/ActiveModel/Serializers/Xml/Serializer/serialize
为什么在序列化行末尾添加"Array"会导致空数组不能保存到数据库中?
SQLite 不支持数组列类型。我认为发生的情况是,当您尝试使用示例属性的空数组保存用户时,它被解释为示例列没有更改。如果您在使用示例数据创建测试用户后尝试此操作,会发生什么情况?
test.example = nil
test.save
Run Code Online (Sandbox Code Playgroud)
或者,这会发生什么?
test.example = [nil]
test.save
Run Code Online (Sandbox Code Playgroud)
解决方案似乎是使用ActiveRecord 回调,例如before_save检查用户模型的示例属性以确定它是否为空数组。如果是这样,请将属性设置为nil或[nil](以有效者为准),然后数据应相应地保留。