【问题标题】:ActiveRecord not saving after updating attribute更新属性后 ActiveRecord 不保存
【发布时间】:2016-04-09 12:20:56
【问题描述】:

我想知道这里是否有我不明白的地方在起作用,或者我是否遇到了 ActiveRecord (4.1.1) 中的错误。

我有一个充满记录的数据库,其中只有一个属性,其中有一个 JSON 字段。我拿了一个并尝试像这样更新它。

test = Submission.find(1)
test.update_attribute('json_data',similar_but_different_json(test.json_data))

假设similar_but_different_json 方法对该JSON 进行了小幅更新。就我而言,我正在修复一些由损坏的表单造成的数据错误。

执行此操作时,我没有收到任何错误,我在控制台中显示了一个提交但没有提交任何数据并返回 true

为了真正更新记录,我必须这样做。

test = Submission.find(1)
old_json_data = test.json_data
test.json_data = ""
test.json_data = similar_but_different_json(old_json_data)
test.save

似乎正在发生的事情是 ActiveRecord 没有识别出已经进行了必须保存的更改。这可能是为什么将字段设置为空字符串然后返回 JSON 允许保存记录的原因吗?

【问题讨论】:

  • 我还应该提到,这不是 Rails 的完整实现。我将 ActiveRecord 与 Sinatra 一起使用。
  • 我认为update_attribute 已被弃用,而支持update_attributes
  • 已弃用,但update_attributes 也会出现此问题。
  • 我在 Rails 存储库上打开了一个问题,看看它是否有点在记录中。 github.com/rails/rails/issues/15146

标签: ruby-on-rails json activerecord


【解决方案1】:

will_change!

你也可以使用:

test.json_data_will_change!   # Goes before the save.

这将告诉 ActiveModel 属性 json_data 已更改(即它是 ← 某处有一个笑话)并将在保存时正确更新值。

有关更多详细信息,请参阅Rails is not saving an attribute that is changed

【讨论】:

    【解决方案2】:

    我不明白为什么该对象没有被标记为脏。一种解决方法是使用update_columns:

    test.update_columns(json_data: similar_but_different_json(test.json_data))
    

    它将直接在 DB 中执行 UPDATE 查询,无需任何验证、脏检查等...json_data 字段不能是只读的。

    【讨论】:

    • 该解决方案确实有效。这是一行,而不是我首先尝试的解决方案,我将字段更改为空字符串,然后返回 JSON。我不熟悉“脏检查”,但它是有道理的。我想知道我是否应该在 Rails Github 存储库上打开一个问题。
    【解决方案3】:

    ActiveModel(4.1.1 版)无法跟踪对属性的“内联”修改。

    您的 'similar_but_different_json' 方法可能正在对字符串进行内联修改。

    在修改之前复制字符串。

    test = Submission.find(1)
    test_json_data_duplicate = test.json_data.dup 
    test.update_attribute('json_data',similar_but_different_json(test_json_data_duplicate))
    

    当你...

    test.json_data = ""
    

    ... ActiveModel 可以捕获更改,因为您将其设置为一个恰好为空的新 String 对象。因此,当您调用 update_attribute 时,模型已经知道该属性已更改。

    如果您尝试以内联方式清空字符串,您的技巧将不起作用。

    test = Submission.find(1)
    old_json_data = test.json_data
    test.json_data.clear # Instead of test.json_data = ""
    test.json_data = similar_but_different_json(old_json_data)
    test.save
    

    ActiveModel::Dirty

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多