如何编写 Rake 任务以将数据导入 Rails 应用程序?
Posted
技术标签:
【中文标题】如何编写 Rake 任务以将数据导入 Rails 应用程序?【英文标题】:How to write Rake task to import data to Rails app? 【发布时间】:2011-03-21 17:45:59 【问题描述】:目标:使用 CRON 任务(或其他预定事件)更新数据库,每晚从现有系统导出数据。
所有数据都在现有系统中创建/更新/删除。该网站不直接与该系统集成,因此 rails 应用程序只需要反映数据导出中出现的更新。
我有一个包含约 5,000 种产品的 .txt
文件,如下所示:
"1234":"product name":"attr 1":"attr 2":"ABC Manufacturing":"2222"
"A134":"another product":"attr 1":"attr 2":"Foobar World":"2447"
...
所有值都是用冒号 (:
) 分隔的双引号 ("
) 括起来的字符串
字段是:
id
:唯一标识;字母数字
name
:产品名称;任何字符
属性列:字符串;任何字符(例如,大小、重量、颜色、尺寸)
vendor_name
:字符串;任何字符
vendor_id
:唯一的供应商 ID;数字
供应商信息在当前系统中没有规范化。
这里有哪些最佳做法?是否可以删除产品和供应商表并在每个周期使用新数据重写?还是只添加新行并更新现有行更好?
注意事项:
-
此数据将用于生成
Orders
,该数据将通过夜间数据库导入持续存在。 OrderItems
需要连接到数据文件中指定的产品 ID,因此我们不能依赖自动递增的主键来确保每次导入都相同;需要使用唯一的字母数字 ID 将 products
连接到 order_items
。
理想情况下,我希望进口商标准化供应商数据
我不能使用普通 SQL 语句,所以我想我需要编写一个 rake
任务才能使用 Product.create(...)
和 Vendor.create(...)
样式语法。
这将在 EngineYard 上实现
【问题讨论】:
【参考方案1】:我不会在每个周期都删除产品和供应商表。这是一个轨道应用程序吗?如果是这样的话,有一些非常好的 ActiveRecord 助手会派上用场。
如果你有一个产品活动记录模型,你可以这样做:
p = Product.find_or_initialize_by_identifier(<id you get from file>)
p.name = <name from file>
p.size = <size from file>
etc...
p.save!
find_or_initialize 会根据你指定的 id 在数据库中查找产品,如果找不到,它会创建一个新的。这样做的真正方便之处在于,ActiveRecord 只会在任何数据发生更改时保存到数据库中,并且它会相应地自动更新您在表 (updated_at) 中拥有的任何时间戳字段。还有一件事,因为您将通过标识符(文件中的 id)查找记录,所以我会确保在数据库中的该字段上添加一个索引。
要创建一个 rake 任务来完成此任务,我会将一个 rake 文件添加到您的 rails 应用程序的 lib/tasks 目录中。我们将其称为 data.rake。
在 data.rake 中,它看起来像这样:
namespace :data do
desc "import data from files to database"
task :import => :environment do
file = File.open(<file to import>)
file.each do |line|
attrs = line.split(":")
p = Product.find_or_initialize_by_identifier(attrs[0])
p.name = attrs[1]
etc...
p.save!
end
end
end
要调用 rake 任务,请在命令行中使用“rake data:import”。
【讨论】:
我试过这个,但我收到了错误undefined local variable or method 'data' for main:Object
。有什么想法为什么会发生这种情况?
问题是namespace data do
必须更改为namespace :data do
。【参考方案2】:
由于产品并不会经常更改,因此我认为最好的方法是仅更新更改的记录。
-
获取所有增量
使用单个 SQL 语句进行大规模更新
如果您在模型中包含规范化代码,则可以使用 Product.create 和 Vendor.create ,否则它只会是矫枉过正。此外,考虑在单个 SQL 事务中插入多条记录,它的速度要快得多。
【讨论】:
如我的问题中所述,我不能使用普通 SQL 语句。【参考方案3】: 创建一个 cronned 的导入器 rake 任务 使用 Faster CSV 或通过 vanilla ruby 逐行解析文件,例如:file.each 做 |line| products_array = line.split(":") 结束
在“:”上分割每一行并推入一个散列使用 find_or_initialize 填充您的数据库,例如:
Product.find_or_initialize_by_name_and_vendor_id("foo", 111)
【讨论】:
你为什么使用find_or_initialize_by_name_and_vendor_id
?这是否建议产品accepts_nested_attributes_for :vendor
?以上是关于如何编写 Rake 任务以将数据导入 Rails 应用程序?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 kubernetes cron 作业中启动 rails rake 任务
如何在 Rails 中使用环境将参数传递给 Rake 任务? [复制]