更新Rails 4和PostgreSQL json列中的单个键/值对?

Ran*_*ess 16 postgresql json ruby-on-rails hstore

我有一个相当大的json文档,我必须存储在我的应用程序中的每个Evaluation实例的字段中.随着时间的推移,应用程序上的某些操作将要求我更改文档中的各种键/值对.Rails 4和PostgreSQL json数据类型似乎是这个问题的理想选择,但我无法对数据库进行更改.

这是一个缩写的工作流程:

我有一个json文件,我导入每个评估记录的字段:

// example.json
{ "question_1":"no" }
Run Code Online (Sandbox Code Playgroud)

我创建一个记录并导入json:

>> evaluation = Evaluation.create assessments: File.read("example.json")
>> evaluation.assessments = File.read("#{Rails.root}/example.json")
=> "{ \"question_1\":\"no\" }"
Run Code Online (Sandbox Code Playgroud)

调用评估字段似乎工作正常:

>> evaluation.assessments
=> {"question_1"=>"no"}

OR

>> evaluation.assessments["question_1"]
=> "no"
Run Code Online (Sandbox Code Playgroud)

例1

改变json不是很好.这实际上没有提交任何东西:

>> evaluation.assessments["question_1"] = "yes"
=> "yes"

>> evaluation.assessments["question_1"]
=> "yes"

>> evaluation.save
   (0.3ms)  BEGIN
   (0.2ms)  COMMIT
=> true
Run Code Online (Sandbox Code Playgroud)

例#2

替换为一个全新的对象确实提交:

>> evaluation.assessments = {"question_1"=>"yes"}
=> {"question_1"=>"yes"}

>> evaluation.save
(0.3ms)  BEGIN
SQL (0.7ms)  UPDATE "evaluations" SET "assessments" = $1, "updated_at" = $2 WHERE "evaluations"."id" = 1  [["assessments", "{\"question_1\":\"yes\"}"], ["updated_at", "2014-08-21 00:52:03.581817"]]
(3.8ms)  COMMIT
=> true
Run Code Online (Sandbox Code Playgroud)
  • 我在示例#1中做错了什么?
  • evaluation.assessment当我调用它时,为什么数据库不会提交我对列所做的更改,更改值,并在实例上调用save?

Ran*_*ess 33

由于与ActiveRecord相关的已知错误不知道更改的属性是脏的,因此最终成为一个简单的修复:

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

这是解决方案:

>> evaluation.assessments["question_1"] = "yes"
=> "yes"

>> evaluation.assessments_will_change!
>> evaluation.save
(1.1ms)  BEGIN
SQL (1.6ms)  UPDATE "evaluations" SET "assessments" = $1, "updated_at" = $2 WHERE "evaluations"."id" = 4  [["assessments", "{\"question_1\":\"yes\"}"], ["updated_at", "2014-08-21 01:59:47.331216"]]
(2.5ms)  COMMIT
=> true
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,我正在努力解决这个问题.甚至没想到认为ActiveRecord有问题...... (2认同)
  • 在 Rails 5 中,无论您是更新现有密钥还是添加新密钥,只需执行一个简单的“merge!”,然后执行“save”即可。 (2认同)