我正在解析 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
几千次 - 以及随后的数据库 INSERT
s - 并不便宜),我建议检查出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/