我有一个模型“Item”,我想生成一堆包含从CSV文件中获取的数据的Items。但我想允许用户选择使用哪些数据列。
所以我的模型“User”有一个名为Columns的json属性,告诉我应该从该用户的CSV文件中使用哪些列。例如,如果user.columns == {"title"=>"true","category"=>"false"}
,则应使用“标题”列,但不应使用“类别”列。
(或者,我只能列出我想要包含的列,如下所示:{"title"=>"included"}
,然后执行user.columns.each {|c| c[0]}
之类的操作以获取所有包含列的数组。)
我有一种基于CSV数据生成项目的方法:
def create
#...
SmarterCSV.process(file).each do |row| #this line returns an array of all the rows in the CSV file
Item.create(title: row[:title], category: row[:category])
end
end
但是如何根据user.columns
的内容修改方法的参数?对于{"title"=>"true","category"=>"false"}
示例,该方法只是Item.create(name: row[:title])
。是否可以动态生成类似的方法?
我打算有很多可能的列,所以对每种可能性做一个if
条件是不可行的。
答案 0 :(得分:2)
Item.create(name: row[:name])
也会使用哈希值,并且可以等效地编写为Item.create({ name: row[:name] })
因此 - 您可以每次在哈希中构建整个对象;然后slice
关闭您不想要的任何属性,然后传递给create
。所以假设你有:
user.columns
#=> {"name"=>"true","category"=>"false"}
然后你可以写:
user_object = { "name" => row[:name], "category" => row[:category] }
#=> include all the possible attributes here
included_attributes = user.columns.select { |k, v| v == "true" }
#=> {"name"=>"true"}
Item.create( user_object.slice(*included_attributes.keys) )
#=> `Item` is created with only `name` attribute
编辑:正如engineermnky在评论中指出的那样,row
已经是哈希。这进一步简化了它,你可以改为:
SmarterCSV.process(file).each do |row|
included_attributes = user.columns.select { |k, v| v == "true" }
Item.create( row.slice(*included_attributes.keys) )
end
答案 1 :(得分:1)
我会在User
模型中添加一个方法,将列名称作为符号返回:
class User
def selected_columns
columns.select{|_,v| v == "true"}.keys.map(&:to_sym)
end
end
然后像这样修改项目创建:
Item.create(row.slice(*user.selected_columns))