【问题标题】:The best way to export rails database data导出rails数据库数据的最佳方式
【发布时间】:2017-10-22 17:04:16
【问题描述】:

铁路 5.1

我有一个使用 PostgreSQL 作为数据库的 RAILS 应用程序。我想从 RAILS 角度导出/转储 RAILS 数据库数据。所以我独立于数据库。稍后我想使用这个导出/转储文件将数据加载/导入/播种回数据库。

我尝试过以下 GEM:

  • 种子转储
    它可以工作,但不能处理 HABTM 模型关系。

  • yaml_db , 它可以工作,但 yaml 格式不是 rails db:seed

  • 理解的格式

【问题讨论】:

  • 只需使用pg backups tools。 “从 RAILS 的角度来看”的事情听起来就像你在同一个数据库中存储了一堆其他垃圾 - 不要。
  • 不,我只将此数据库用于此 RAILS 应用程序。这个数据库中没有保存其他一堆垃圾。 pg 备份工具以 postgreSQL 特定的 sql 转储格式存储数据库数据,不能用于加载到 MySQL 数据库中。这是“从 RAILS 角度”保存数据库数据时的一大优势。
  • 如果要部署到 postgres,请不要使用 mysql 进行测试/开发。您的开发环境应尽可能地反映您的生产。问题解决了。
  • "例如,避免在开发和生产之间使用不同的服务,即使适配器理论上抽象出服务中的任何差异。在生产中使用本地 SQLite 和 PostgreSQL;或者在开发和 Memcached 中使用本地进程内存进行缓存在生产中,起初可能看起来无害,但可能会导致各种生产问题。”。这是来自Heroku docs,但普遍适用。
  • MySQL 和 Postgres 之间存在许多现实世界的差异,这些差异可能会导致大问题。 MySQL 是出了名的松懈,它允许 Postgres 不允许的许多模棱两可的查询。

标签: ruby-on-rails ruby-on-rails-5


【解决方案1】:

这是一个导出为 JSON 的实际示例。我使用 rake 任务来做这种事情。在此示例中,我正在转储用户表。

namespace :dataexport do
  desc 'export sers who have logged in since 2017-06-30'
  task :recent_users => :environment do
    puts "Export users who have logged in since 2017-06-30"

    # get a file ready, the 'data' directory has already been added in Rails.root
    filepath = File.join(Rails.root, 'data', 'recent_users.json')
    puts "- exporting users into #{filepath}"

    # the key here is to use 'as_json', otherwise you get an ActiveRecord_Relation object, which extends
    # array, and works like in an array, but not for exporting
    users = User.where('last_login > ?', '2017-06-30').as_json

    # The pretty is nice so I can diff exports easily, if that's not important, JSON(users) will do
    File.open(filepath, 'w') do |f|
      f.write(JSON.pretty_generate(users))
    end

    puts "- dumped #{users.size} users"
  end
end

然后导入

namespace :dataimport do
  desc 'import users from recent users dump'
  task :recent_users => :environment do
    puts "Importing current users"

    filepath = File.join(Rails.root, 'data', 'recent_users.json')
    abort "Input file not found: #{filepath}" unless File.exist?(filepath)

    current_users = JSON.parse(File.read(filepath))

    current_users.each do |cu|
      User.create(cu)
    end

    puts "- imported #{current_users.size} users"
  end
end

有时作为导入过程的一部分,我需要一个干净的表来导入,在这种情况下,我会以以下方式开始任务:

ActiveRecord::Base.connection.execute("TRUNCATE users")

这不是处理非常大的表格的最佳方式,表格超过 50,000 行和/或包含大量文本字段。在这种情况下,数据库原生转储/导入工具会更合适。

为了完整起见,这里是一个 HABTM 示例。仍然有一个链接表,但它没有模型,所以使用它的唯一方法是原始 SQL。假设我们的用户有很多角色,反之亦然(用户 M:M 角色),例如:

class User < ApplicationRecord
  has_and_belongs_to_many :roles
end

class Role < ApplicationRecord
  has_and_belongs_to_many :users
end

必然会有一个名为users_roles 的连接表,它有两列,user_idrole_idSee the Rails Guide on HABTM

要导出,我们必须直接执行SQL:

users_roles = ActiveRecord::Base.connection.execute("SELECT * from users_roles").as_json
# and write the file as before

并执行SQL导入

# read the file, same as before
user_roles.each do |ur|
  ActiveRecord::Base.connection.execute("insert into users_roles (user_id, role_id) values ('#{ur[0]}', '#{ur[1]}')")
end

See this answer for more on inserting with raw SQL

【讨论】:

  • 哦,在 Ryan 的解释之后,它似乎没有我想象的那么复杂。我明白。以及如何保存 HABTM 和 Has_many_through 关系?
  • 在关系 M:M 关系、HABTM 或 has_many/through 的情况下,您将导出所有三个表。 “关系”是连接表中的外键。在导入期间,将使用保存在导出中的 ID(主键)创建记录,前提是它与现有 ID 不冲突。并且只要 ID 相同,连接表中的键将继续工作。请注意,在 Rails 4 之前,您需要使用 User.create(cu, :without_protection =&gt; true) 来确保 ID 被完整导入
  • 您能否举一个实际的例子如何导出HABTM,Has_many/through关系? HABTM 没有可以像 User.where().as_json 这样使用的模型。
  • 至于HABTM,我不喜欢,有一次试了,30分钟后撕掉了。它与 has_many/through 相比并没有特别的优势,但也有一些明显的缺点,例如,当然,连接表没有模型。要对它做任何事情,您需要查看原始 SQL,这很好,但我喜欢让 ActiveRecord 来完成这项工作。不过,我已经更新了答案。
  • 非常感谢您完成这个基于 json 的转储/加载方法。对于我的 RAILS 应用程序,我对 HABTM 感觉很好,它运行良好。当我想从 RAILS 角度转储我的完整 RAILS 数据库数据时,我不得不采用这种原始 SQL 方式,还包括 HABTM 隐藏连接表。但后来我有优势编辑基于 json 的备份文件并通过 rails 任务加载完整的 RAILS 应用程序。
【解决方案2】:

我同意人们所说的使用内置数据库工具来做到这一点。或者弄清楚是否有办法告诉数据库导出为 CSV,然后以这种方式导入。

然而,如果您真的想要一种与数据库无关的方式,这里有另一种方式:使用您自己的 API。

我的意思是,在 2017 年,您的 Rails 应用程序真的不应该只输出 HTML,还应该输出 JSON。也许你将来想写一个 SPA 类型的应用程序,或者一个移动应用程序。确保除了 HTML 版本之外还有对象的 Javascript 表示是一个好主意。

因此,如果您的应用中有 /projects,请编写一个脚本,以 JSON 格式请求 /projects。将每个对象保存为自己的文件,然后在您的远程系统中将所有内容重新发布。

如果 JSON 表示中没有任何内容(即您没有列出项目中的所有用户),请确保也访问这些端点并将所有内容保存到单独的 JSON 文件中。

然后编写一个播放器脚本,将所有这些文件发布到您的目标服务。

这是一种方法。还有另一种方法是在 ActiveRecord 中完全用 Ruby 编写它——这可能作为某种用户数据导出功能有用,所以这也可能是一种很棒的方法,但在我看来,“我们可以构建一个 Javascript 前端吗?或移动应用程序?”之前通常会被问到,“用户可以把他们的数据拿出来吗”;)

【讨论】:

  • 嗨瑞恩,感谢您的回复。目前,我的 RAILS 应用程序仅显示为 HTML。移动设备的代表将在明年晚些时候推出。所以我不想编写额外的代码,只是为了转储/导出我的数据库日期。 GEM seed_dump 充其量符合我的需求,但与 HABTM 关系很矛盾。我正在寻找类似 seed_dump 的 GEM。
猜你喜欢
  • 1970-01-01
  • 2011-10-09
  • 2010-09-17
  • 1970-01-01
  • 2012-05-22
  • 1970-01-01
  • 1970-01-01
  • 2015-02-04
  • 2023-03-16
相关资源
最近更新 更多