从文件中读取json序列化对象

时间:2013-04-20 11:59:58

标签: ruby-on-rails ruby ruby-on-rails-3.2

我的目标是将一组对象序列化为一个文件,以便创建一个备份。我开始工作,使用模型上的方法(这里简化,假设我有两个ActiveRecords foo和bar):

def backup(file, foo, bar)  
  file.write(foo.to_json(root: true))
  file.write(bar.to_json(root: true))  
end  

这给了我一个我想要的文件,在这种情况下有两个记录:

{"foo":{"Account_id":1,"Name":"F","created_at":"2013-04-16T10:06:19Z","id":1,"updated_at":"2013-04-20T11:36:23Z"}}  
{"bar":{"Account_id":1,"Name":"B","created_at":"2013-04-16T10:06:19Z","id":1,"updated_at":"2013-04-20T11:36:23Z"}}  

稍后我想要读取该备份并重新实例化这些对象,然后可能会将它们保存回数据库。我的目标是遍历文件检查每个对象的类型,然后实例化正确的对象。

我有部分逻辑,但还没有全部,我没有弄清楚在实例化之前我如何确定每个序列化对象的类型。我还原的代码如下:

def restore(file)
  file.each_line do |line|  
    **<some magic that parses my line into objectType and objectHash>**
    case objectType
    when :foo
      Foo.new.from_json(objectHash)
      Foo.process
      Foo.save!
    when :bar
      Bar.new.from_json(objectHash)
      Bar.process
      Bar.save!
    end
  end
end  

我正在寻找的是“某些神奇”部分的内容。我可以直接编写代码来解析行,以确定它是foo还是bar,但我觉得可能有一些棘手的Rails / Ruby方法可以自动完成。不幸的是,在这种情况下,谷歌不是我的朋友。我只能看到在Web请求中关注json的页面,但不会以这种方式解析json。有什么我缺少的,或者我应该编写代码直接拆分字符串并读取对象类型?

如果我写代码直接拆分字符串,我会写下以下内容:

objectType = line[/^{"(\w*)"=>(.*)}/, 1]  
objectHash = line[/{"(\w*)"=>(.*)}/, 2]

这非常难看,我确信有一种更好的方法(我仍在研究),但我不确定这是否是正确的方法v有自动查看json表示的东西并从根值知道要实例化的对象。

最后,使用from_json的实际实例化也不起作用,它不会填充ActiveRecord上的任何字段。它给了我nil参数,所以我认为解析语法不正确。

所以,这提出了三个问题:

  1. 有没有办法确定我只是缺少哪个对象,哪个更干净?
  2. 如果没有,我需要使用正则表达式,是否有一种语法可以在一次运行中解析该行的两个位,而不是我的两行具有相同的正则表达式?
  3. from_json语法显得不高兴。我在这里缺少一种语法吗? (不再是一个问题 - 上面的代码是固定的,我应该使用as_json,当它应该是to_json时,尽管文档还不清楚......)
  4. (注意:随着时间的推移编辑以澄清我的问题,因为我现在有一个正常的正则表达式(之前没有),但仍然不确定它是否非常优雅。)

    进一步的信息 - 这里的一个问题,正如我进一步深入研究的那样,as_json实际上并没有给我json - 我在文件中的内容是哈希,而不是json。此外,散列中的created_at和lastupdated_at的值不会被引用 - 所以基本上这就是导致解析失败的原因。我已经知道我应该使用to_json而不是as_json,尽管文档表明as_json应该可以工作。

2 个答案:

答案 0 :(得分:0)

我不确定我是否完全理解你的方法论,但我认为使用JSON.parse()会有所帮助。

这里有一些很好的信息http://mike.bailey.net.au/2011/02/json-with-ruby-and-rails/

这可以帮助您将原始对象转换回哈希值。

答案 1 :(得分:0)

好的,所以我觉得我有一些有用的东西。我完全不相信它优雅,但它给了我结果。我会花一些时间试图让它更清洁。

代码如下所示:

file.each_line do |line|
  objectType = line[/^{"(\w*)":(.*)}/, 1]
  objectJSON = line[/{"(\w*)":(.*)}/, 2]
  objectHash = JSON.parse(objectJSON)
  case objectType
  when 'foo'
    restoredFoo = Foo.new(objectHash.except('id', 'created_at', 'updated_at'))
    restoredFoo.created_at = objectHash['created_at']
    restoredFoo.updated_at = objectHash['updated_at']
    restoredFoo.save!
  end
  when 'bar'
    restoredBar = Bar.new(objectHash.except('id', 'created_at', 'updated_at'))
    restoredBar.created_at = objectHash['created_at']
    restoredBar.updated_at = objectHash['updated_at']
    restoredBar.save!
  end
end

注意事项:

  1. 我觉得应该有一种方法来创建不是JSON.parse的对象,而是在模型上使用from_json方法。如果没有这样做,我不确定from_json的用途是什么!!
  2. 我很开心mass_assignment。我真的不想使用:without_protection =&gt;是的,虽然这是一个选择。我担心的是我确实想要将created_at和updated_at恢复原状,但我想要一个新的id。我将在我的应用程序中为许多实体执行此操作,我真的不想最终复制代码中的attributes_protected - 它似乎不是很干“
  3. 我仍然非常确定我的reg exp可以在一次调用中为我提供objectType和objectJSON
  4. 但是说了这么多,它确实有效,这是一个很好的一步。