Ruby: 如果列存在则使用它,如果不存在则添加到其他列
Ruby: If column exists use it, if not add to other column
我正在解析 CSV 并试图区分将添加到 JSONB :data
列的 Model
和 "virtual" 列中的列。到目前为止,我得到了这个:
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) }
你试过了吗:
row[:data] = row.delete_if {|k,v| !Model.attribute_method?(k) }
Model.create(row)
这将从行散列中删除元素,并将键值对添加回 :data
键下的行。
你可以试试这个has_attribute?
row[:data] = row.keep_if { |x| !Model.has_attribute?(x) }
有多种方法可以做到这一点。一种特别直接的方法是使用来自 Rails' ActiveSupport 扩展的 Hash#slice!
,它的工作方式类似于 Array#slice!
和 returns 一个带有参数中未给出的键的哈希,而保留给定的密钥:
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
P.S。这可能会在 "Stupid Ruby Tricks," 下归档,但如果您使用的是 Ruby 2.0+,则可以利用双拼音 (**
) 来实现这种紧凑的结构:
rows.each do |row|
Model.create(data: row.slice!(*attrs), **row)
end
P.P.S。如果您的 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 文档中还有其他更快的选项。
我正在解析 CSV 并试图区分将添加到 JSONB :data
列的 Model
和 "virtual" 列中的列。到目前为止,我得到了这个:
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) }
你试过了吗:
row[:data] = row.delete_if {|k,v| !Model.attribute_method?(k) }
Model.create(row)
这将从行散列中删除元素,并将键值对添加回 :data
键下的行。
你可以试试这个has_attribute?
row[:data] = row.keep_if { |x| !Model.has_attribute?(x) }
有多种方法可以做到这一点。一种特别直接的方法是使用来自 Rails' ActiveSupport 扩展的 Hash#slice!
,它的工作方式类似于 Array#slice!
和 returns 一个带有参数中未给出的键的哈希,而保留给定的密钥:
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
P.S。这可能会在 "Stupid Ruby Tricks," 下归档,但如果您使用的是 Ruby 2.0+,则可以利用双拼音 (**
) 来实现这种紧凑的结构:
rows.each do |row|
Model.create(data: row.slice!(*attrs), **row)
end
P.P.S。如果您的 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 文档中还有其他更快的选项。