如何为create方法动态生成参数?

时间:2017-06-06 17:28:17

标签: ruby-on-rails ruby dynamic ruby-on-rails-5

我有一个模型“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条件是不可行的。

2 个答案:

答案 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))