ruby-on-rails - Ruby : If column exists use it, 如果不添加到其他列

标签 ruby-on-rails csv ruby-on-rails-4 jsonb smartercsv

我正在解析 CSV 并尝试区分 Model 中的列和将添加到 JSONB :data 列的“虚拟”列。到目前为止,我得到了这个:

rows = SmarterCSV.process(csv.path)
rows.each do |row|
  row.select! { |x| Model.attribute_method?(x) } # this ignores non-matches
  Model.create(row)
end

从 CSV 行中删除Model 不匹配的列。相反,我想将所有这些数据添加到 Model 中名为 :data 的列中。我该怎么做?

编辑

select! 之前可能是这样的吗?

row[:data] = row.select { |x| !Model.attribute_method?(x) }

最佳答案

有多种方法可以做到这一点。一种特别直接的方法是使用 Hash#slice!来自 Rails 的 ActiveSupport 扩展,它的工作方式类似于 Array#slice! 并返回一个散列,其中包含那些未在其参数中给出的键,同时保留给定的键:

rows = SmarterCSV.process(csv.path)
attrs = Model.attribute_names.map(&:to_sym)

rows.each do |row|
  row[:data] = row.slice!(*attrs)
  Model.create(row)
end

附言这可能会在“愚蠢的 Ruby 技巧”下归档,但如果您使用的是 Ruby 2.0+,则可以利用双标 (**) 来实现这种紧凑的结构:

rows.each do |row|
  Model.create(data: row.slice!(*attrs), **row)
end

附言如果您的 CSV 很大并且您发现自己有性能问题(调用 create 几千次 - 以及随后的数据库 INSERTs - 并不便宜),我建议检查出activerecord-import gem .它正是为这类事情而设计的。有了它你会做这样的事情:

rows = SmarterCSV.process(csv.path)
attrs = Model.attribute_names.map(&:to_sym)

models = rows.map do |row|
  row[:data] = row.slice!(*attrs)
  Model.new(row)
end

Model.import(models)

activerecord-import 文档中还有其他更快的选项。

关于ruby-on-rails - Ruby : If column exists use it, 如果不添加到其他列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32367502/

相关文章:

ruby-on-rails - 使用特定 json 键上的 Postgresql json 列过滤 ActiveAdmin

ruby-on-rails - Rails 未定义方法 `map' for nil :NilClass - form collection_select

用于下载 csv 文件的 Javascript 在 FireFox 中不起作用

ruby-on-rails-4 - 无法获取 flickr 图片

ruby-on-rails - 强制 $ rake db :reset Despite Other Users with Postgres

html - 如何将整个 pdf 页面背景色白色更改为 rails 中的其他颜色

javascript - jQuery 事件处理程序无法正常工作

ruby-on-rails - 如何使用searchkick设置word_middle区分大小写的搜索?

使用 XSLT 将 XML 转换为 CSV,用于单个标记中由空格分隔的多个记录

c# - CSV实际上是....分号分隔值...(AZERTY上的Excel导出)