1

我的目标是将一组对象序列化到一个文件中以创建备份。我已经开始使用模型上的方法(在这里简化,假设我有两个 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 方法可以自动执行此操作。不幸的是,在这种情况下,谷歌不是我的朋友。我所能看到的只是网页请求中专注于 json 的页面,但没有以这种方式解析 json。有什么我遗漏的,还是我应该编写代码直接拆分字符串并读取对象类型?

如果我确实编写代码来直接拆分字符串,我会写一些类似的东西:

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

这很丑陋,我确信有更好的方法(我仍在研究),但我不确定这甚至是正确的方法 v 有一些东西可以自动查看 json 表示并从根值要实例化什么对象。

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

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

  1. 有没有办法确定我刚刚丢失的对象是哪个,更干净?
  2. 如果没有并且我需要使用正则表达式,是否有一种语法可以一次性解析行的两个位,而不是我的两行具有相同的正则表达式?
  3. from_json 语法看起来不太好。我在这里缺少语法吗?(不再是一个问题 - 上面的代码是固定的,当它应该是 to_json 时我使用的是 as_json,尽管文档对此相当不清楚......)

(注意:随着时间的推移进行编辑以澄清我的问题,并且因为我现在有一个有效的正则表达式(以前没有),但仍然不确定它是否非常优雅。)

更多信息——这里的问题之一,当我进一步深入研究时,as_json 实际上并没有给我 json——我在文件中拥有的是一个哈希,根本不是 json。此外,散列中 created_at 和 lastupdated_at 的值没有被引用 - 所以基本上这就是导致解析失败的原因。我已经确定我应该使用 to_json 而不是 as_json,尽管文档表明 as_json 应该可以工作。

4

2 回答 2

0

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

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

这将帮助您将原始对象转换回散列。

于 2013-04-20T12:15:58.030 回答
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 => true,尽管这是一个选项。我担心的是我确实希望将 created_at 和 updated_at 恢复原样,但我想要一个新的 id。我将为我的应用程序中的许多实体执行此操作,我真的不想最终复制代码中的 attributes_protected - 它似乎不是很干燥
  3. 我仍然很确定我的 reg exp 可以在一次调用中同时给我 objectType 和 objectJSON

但是说了这么多,它起作用了,这是向前迈出的一大步。

于 2013-04-21T06:42:46.600 回答