【问题标题】:How can I dynamically generate parameters for a create method?如何为创建方法动态生成参数?
【发布时间】:2017-06-06 17:28:17
【问题描述】:

我有一个模型“项目”,我想使用从 CSV 文件中获取的数据生成一堆项目。但我想让用户选择使用哪些数据列。

所以我的模型“用户”有一个名为 Columns 的 json 属性,告诉应该从该用户的 CSV 文件中使用哪些列。例如,如果user.columns == {"title"=>"true","category"=>"false"},则应使用 Title 列,但不应使用 Category 列。 (或者,我可以只列出我想要包含的列,如下所示:{"title"=>"included"},然后执行user.columns.each {|c| c[0]} 之类的操作以获取所有包含列的数组。)

我有一个基于 CSV 数据生成 Items 的方法:

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 条件是不可行的。

【问题讨论】:

  • 我不清楚列名与create 参数中所需内容之间的映射。但您似乎应该修改 user.columns 以返回其他内容(或提供其他用户方法)
  • @MarkThomas 抱歉,如果我不清楚,我想根据user.columns 的内容为我的create 操作生成参数。例如,如果user.columns = {"included_column"=>"true", "another_included_column"=>"true", "not_included_column"=>"false"},则create 参数将为Item.create(included_column: row[:included_column], another_included_column: row[:another_included_column])。那有意义吗? not_included_column 不会是参数,因为它在 user.columns 中是错误的
  • row 包含什么?
  • @MarkThomas 一行只是 CSV 文件的一行。它将包含一堆不同的值,包括“名称”、“类别”和“标签”。
  • 在您的示例中,您有 "title"=>"true" 导致带有键 :name 的散列。这就是让我失望的原因。

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


【解决方案1】:

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

编辑: 正如 Engineersmnky 在 cmets 中指出的那样,row 已经是一个哈希值。这进一步简化了它,您可以改为:

SmarterCSV.process(file).each do |row|
  included_attributes = user.columns.select { |k, v| v == "true" }
  Item.create( row.slice(*included_attributes.keys) )
end

【讨论】:

  • 行已经是Hash 并且有namecategory 的键,为什么不直接利用它呢?
  • keys.map(&:to_sym) :) 因为“行”键显然是符号,而列键是字符串。要么用symbolize_keys预处理user.columns
  • 太棒了!谢谢。
【解决方案2】:

我会在您的 User 模型中添加一个方法以将列名作为符号返回:

class User
  def selected_columns
    columns.select{|_,v| v == "true"}.keys.map(&:to_sym)
  end
end

然后像这样修改您的项目创建:

Item.create(row.slice(*user.selected_columns))

【讨论】:

    猜你喜欢
    • 2011-01-14
    • 2016-11-09
    • 2011-01-22
    • 2021-12-05
    • 1970-01-01
    • 2013-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多