【问题标题】:Cannot save empty array to database when serialized序列化时无法将空数组保存到数据库
【发布时间】:2015-08-09 22:32:02
【问题描述】:

在 Ruby on Rails 中,具有序列化数组字段的模型将不会在 .save() 上更新,如果该数组为空,则它之前有数据。

我正在使用:

  • Ruby 2.2.1

  • Rails 4.2.1

  • sqlite3 1.3.10

    我创建了一个新模型,其中一个字段设置为文本:

    rails g model 用户名:字符串示例:文本

在我添加的 User.rb 文件中:

serialize :example, Array

我实例化了 User 类的一个新实例:

test = User.new
<User id: nil, name: nil, example: [], created_at: nil, updated_at: nil>

然后我保存用户以确保它正确保存:

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

并在其中添加了一些数据,以使其感到快乐和有目的:

test.example.push(1)
test.example.push(2)

然后保存起来:

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

并确保一切都保存完好:

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">

我删除了一项,验证它已被删除,然后保存它,确保 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

我从数组中删除了最后一条数据,验证了空数组并保存了它。请注意缺少 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

多次保存得到相同的结果。一个新的 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">

解决方法是从模型中的序列化行中删除“数组”,将字段初始化为 nil。但这意味着我第一次将数据添加到新实例时,我必须手动将字段设置为空数组 (test.example = []) 以便在其上调用 .push()。在此设置中一切正常,新清空的数组愉快地保存到数据库中。

我在 Rails Github 上看到一个已关闭的问题,表明应始终保存序列化的列,但不知道这是否相关:

https://github.com/rails/rails/issues/8328

我无法从序列化源代码中辨别出任何可以启发我的东西:

http://apidock.com/rails/ActiveModel/Serializers/Xml/Serializer/serialize

为什么在序列化行末尾添加“Array”会导致空数组无法保存到数据库中?

【问题讨论】:

  • 欢迎来到 Stack Overflow。以下是一些编写问题的技巧: 不要添加“Ruby on Rails”或类似标签。 Stack Overflow(和搜索引擎)使用您为问题定义的标签。相反,只需写一个简短的描述性句子。在正文中,不必使用标题。取而代之的是正常写作,就像给同事写信一样。 Stack Overflow 有点像编程问答的百科全书,但风格不那么正式。模仿其他问题的风格以保持共同的外观和感觉。还可以学习内联代码格式。
  • 感谢您的建议和编辑!我会记住这个建议以备将来查询。您能详细说明内联代码格式吗?我在帖子中使用控制台输出,因为我认为它最能展示问题。

标签: ruby-on-rails arrays ruby serialization


【解决方案1】:

SQLite 不支持 Array 列类型。我认为发生的情况是,当您尝试使用示例属性的空数组保存用户时,它被解释为示例列没有更改。如果您在使用示例数据创建测试用户后尝试这样做会发生什么?

test.example = nil
test.save

或者,这会发生什么?

test.example = [nil]
test.save

似乎解决方案是使用ActiveRecord callback(例如before_save)来检查用户模型的示例属性以确定它是否为空数组。如果是这样,请将属性设置为 nil[nil](无论哪个有效),然后数据应该相应地保留。

【讨论】:

  • 只要不尝试先保存空白数组,设置和保存为 nil 即可。 [nil] 解决方案也可以保存,但任何 .length 调用都会返回 1,这是非最优的。我在这里的主要希望是弄清楚为什么将 Array 添加到序列化行会在空白保存时产生不同的行为,而不是如果它不存在。我目前的解决方法是单独使用 Serialize,无数组,然后在调用 create 方法时检查“nil”:test.example = [ ] if !test.example
猜你喜欢
  • 1970-01-01
  • 2019-12-03
  • 2014-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多