使用Rails将外部JSON保存到数据库

9

我正在使用gem 'httparty'发起一个向外部资源的GET调用;这是我的Controller.rb代码:

def show
  response = HTTParty.get('URI')
  user = JSON.parse(response)
  user.each {|line| puts line['user']['id']}
  #the "['user']['id']" is because of the nested JSON object that is returned after the 
  parse.
end

这在我的rails控制台中返回了正确的输出,但现在问题是如何将['id']保存到我的数据库中?

目前,我的用户模型具有:id和:name;来自外部API的JSON对象发送:id和:name以及我不需要的大量其他信息。

class User < ActiveRecord::Base
   attr_accessor :id, :name
end

感谢您的帮助!任何帮助都将不胜感激。


1
也许你应该将json的id保存在类似于uri_id的列中,而不是id列中?在这种情况下,只需创建新列并在应用程序中使用即可。我认为这将是最好的选择。 - tiktak
已经注意到了。我会尝试一下;有没有办法循环遍历JSON数组,只保存:uri_id和:name? - asing
2个回答

16

首先,我建议您为ID创建另一列(例如external_id),而不是将其保存在User模型的实际id列中(该列在ActiveRecord中非常重要,您真的不想直接设置它)。您可以验证该列的唯一性,以确保您不会将相同的用户数据导入到数据库中的多个单独记录中。

一旦您有了该列,就在User模型中创建一个类方法(我称之为save_data_from_api)来将JSON数据加载到数据库中:

class User < ActiveRecord::Base

  # optional, but probably a good idea
  validates :external_id, :uniqueness => true

  def self.save_data_from_api
    response = HTTParty.get('URI')
    user_data = JSON.parse(response)
    users = user_data.map do |line|
      u = User.new
      u.external_id = line['user']['id']
      # set name value however you want to do that
      u.save
      u
    end
    users.select(&:persisted?)
  end

end

这段代码的作用:

  • 将JSON数据映射到一个块中 (user_data.map),该块将处理每个JSON用户,并且:
    1. 初始化一个新用户 (User.new)
    2. 为该用户分配JSON数据中的id (line['user']['id'])
    3. 保存新用户 (u.save)
    4. 返回最后一个用户 (u)。
  • 然后,取出结果(赋值给 users),并仅选择实际存在于数据库中(已被持久化)的那些记录 (users.select(&:persisted?))。例如,如果您在external_id上有唯一性约束,并尝试重新加载db数据,则u.save将返回false,记录将不会被创建或重新创建,并且这些结果将从方法返回的结果中过滤掉。

这可能或可能不是您想要的返回值。此外,您可能希望在块中添加更多属性分配(来自JSON数据的name等)。我留给您填写其他细节。


嗨Shioyama,这看起来是我要寻找的解决方案。目前,当我将此代码放入我的项目并打开我的rails控制台时,当我评估User.save_data_from_api时,我会得到一个巨大的JSON字符串。然后,当我评估User.all时,我仍然得到空的“external_id”和“name”= nil值。有什么想法吗? - asing
由于上面的代码仅保存“id”字段,而没有将“external_id”和“name”属性保存到模型中,因此您会获得空值。如果您想将“id”数据保存到“external_id”字段中,则需要将该属性添加到模型中,并将“u.id = line ['user'] ['id']”行更改为“u.external_id = line ['user'] ['id']”。此外,返回值并不是非常重要,但如果您介意,您可以将代码更改为返回模型集合。 - Chris Salzberg
这是一个好问题。它取决于数据的性质:这是一次性的事情,还是您需要定期从API加载用户数据?或者您是否希望数据库基本上始终与API数据同步? - Chris Salzberg
抱歉,但我真的不能再为你提供更多帮助了。最后一个建议是将 u.save 更改为 u.save!,如果保存不成功,它会引发异常,并说明未能保存的原因(假设这是问题所在)。 - Chris Salzberg
1
很高兴能够帮助!在测试模型时,我建议您不要将代码放在控制器操作中,然后通过浏览器访问该操作,而是只需打开Rails控制台(从命令行运行rails c),并在那里尝试。如果出现错误,您将立即得到反馈,这使得调试变得容易。 - Chris Salzberg
显示剩余6条评论

0

在这里我假设您已经创建了uri_id字段来存储外部id,以及name字段来存储用户表中的外部名称。

您的控制器代码 -

def show
  response = HTTParty.get('URI')
  JSON.parse(response).each do |item|
    if (item.id != nil && item.name != nil)
       u = User.new(:uri_id => item.id, :name => item.name)
       u.save
    end
  end
end

谢谢你的回答,Saurabh。但是我没有使用devise。我只是将来自外部API的静态数据填充到我的数据库中。 - asing
如果你的任务变得更简单了,那么现在你只需要获取外部参数并将它们存储到数据库的用户表中。请查看我的更新答案,了解如何循环遍历 JSON,并仅在 :uri_id 和 :name 存在时将外部参数保存到数据库中。 - My God
-1 这个不起作用。你似乎没有读懂 OP 的解释:JSON 数据是嵌套的(其中之一),而且 item.iditem.name 等等也不是访问解析数据的方式。JSON.parse(response) 是一个哈希对象数组,所以你需要使用 item['id']item['name'] 等方式来访问元素。 - Chris Salzberg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接