Ruby on rails 设计-Ruby-根据用户定义的标题从同一数据源创建多个CSV文件

Ruby on rails 设计-Ruby-根据用户定义的标题从同一数据源创建多个CSV文件,ruby-on-rails,ruby,algorithm,design-patterns,architecture,Ruby On Rails,Ruby,Algorithm,Design Patterns,Architecture,我正在研究的要求,我们有大约100+键的散列数据。我们需要根据用户定义的头生成CSV文件,并进行一些转换,我们可能最终拥有100多个模板 主要变化将是 1) 更改列名,例如Fname–>First name 2) 数据转换,如全名–>名字+姓氏(添加2列) 3) 固定立柱的位置–Fname应位于35个位置等 请建议是否可以定义声明方式或任何可用的gem。你能告诉我我们在这里可以采用什么样的设计模式吗 一些示例场景 我有这样的输入,有许多列(100+) 一些客户需要CSV作为 Employee I

我正在研究的要求,我们有大约100+键的散列数据。我们需要根据用户定义的头生成CSV文件,并进行一些转换,我们可能最终拥有100多个模板 主要变化将是 1) 更改列名,例如Fname–>First name 2) 数据转换,如全名–>名字+姓氏(添加2列) 3) 固定立柱的位置–Fname应位于35个位置等

请建议是否可以定义声明方式或任何可用的gem。你能告诉我我们在这里可以采用什么样的设计模式吗

一些示例场景

我有这样的输入,有许多列(100+)

一些客户需要CSV作为

Employee ID, First Name, Last Name, Date of birth, Salary, Bonus
001,John,Dee,10/10/1983,100000,50000,...
002,Alex,Peck,11/01/1988,120000,70000,...
其他(仅标题更改)

另一个(合并列FName、LName->Fullname)

其他(合并薪资、奖金->薪资+奖金列)

其他(列顺序也改变,而不是Dob需要年龄)

就像许多输入相同的变体一样


感谢您的帮助

您需要的是演示者设计模式

您的控制器将请求数据并将其存储在局部变量中,然后您必须为您的客户端加载一个presenter,并将数据变量传递给它。 作为响应,您将获得返回到客户端的最终CSV

假设您的客户机有uniq代码,因此
Client
模型实例有一个
code
属性,它是一个字符串

因此,您的控制器将如下所示:

app/controllers/exports\u controller.rb

类导出控制器data=MyService.fetchData#您需要的是presenter设计模式

您的控制器将请求数据并将其存储在局部变量中,然后您必须为您的客户端加载一个presenter,并将数据变量传递给它。 作为响应,您将获得返回到客户端的最终CSV

假设您的客户机有uniq代码,因此
Client
模型实例有一个
code
属性,它是一个字符串

因此,您的控制器将如下所示:

app/controllers/exports\u controller.rb

类导出控制器data=MyService.fetchData#您可以通过构造一个转换散列来实现您的目标,该散列的键按顺序为所需CSV文件中的列的名称,其值为procs,当使用等于给定散列数组元素的参数调用时,返回要写入CSV文件中与键对应的列中的行中的元素

代码

require 'csv'

def construct_csv(fname, arr, transform)
  CSV.open(fname, "wb") do |csv|
    keys = transform.keys  
    csv << keys  
    arr.each { |h| csv << keys.map { |k| transform[k].call(h) } }
  end  
end  

使用相同的键、相同的顺序和相同的值编写CSV文件

编写一个CSV文件,其中列重新排序1

使用密钥子集编写CSV文件,重命名并重新排序

删除键并添加值已计算的键后,编写CSV文件


一,。我不理解这样做的原因,但这是一个可能的要求。

您可以通过构造一个转换哈希来实现您的目标,该哈希的键是所需CSV文件中的列的名称,按顺序排列,其值是procs,当使用等于给定哈希数组的元素的参数调用时,返回要写入CSV文件中与键对应的列中的行中的元素

代码

require 'csv'

def construct_csv(fname, arr, transform)
  CSV.open(fname, "wb") do |csv|
    keys = transform.keys  
    csv << keys  
    arr.each { |h| csv << keys.map { |k| transform[k].call(h) } }
  end  
end  

使用相同的键、相同的顺序和相同的值编写CSV文件

编写一个CSV文件,其中列重新排序1

使用密钥子集编写CSV文件,重命名并重新排序

删除键并添加值已计算的键后,编写CSV文件


一,。我不明白这样做的原因,但这是一个可能的要求。

选择一些列并重新排序似乎很简单。但是您如何计划用户定义转换呢?在我看来,如果不添加空格,您的示例(全名–>名字+姓氏)就没有意义。但是如果用户想要姓+名,他们可能需要在两者之间加一个逗号。有很多隐藏的复杂性。你能详细说明这一部分吗?如果你能举出一些例子,回答起来就容易多了。从任意散列创建CSV并不困难。看看您是否对rails创建csv文档有很好的了解,这是可能的,并且它是完全可定制的。没有值得推荐的gem。@spickermann使用示例场景进行了更新,感谢您的帮助选择一些列并对它们重新排序似乎很简单。但是您如何计划用户定义转换呢?在我看来,如果不添加空格,您的示例(全名–>名字+姓氏)就没有意义。但是如果用户想要姓+名,他们可能需要在两者之间加一个逗号。有很多隐藏的复杂性。你能详细说明这一部分吗?如果你能举出一些例子,回答起来就容易多了。从任意散列创建CSV并不困难。看看您是否对rails创建csv文档有很好的了解,这是可能的,并且它是完全可定制的。没有可推荐的gem。@spickermann使用示例场景进行了更新,谢谢您的帮助
ID, Fullname, Dob, Salary, Bounus
001,John Dee,10/10/1983,100000,50000,...
002,Alex Peck,11/01/1988,120000,70000,...
ID, FName, LName, Dob, Salary
001,John,Dee,10/10/1983,150000,...
002,Alex,Peck,11/01/1988,190000,...
FName, LName, ID, age, Salary
John,Dee,001,36,150000,...
Alex,Peck,003,32,190000,...
require 'csv'

def construct_csv(fname, arr, transform)
  CSV.open(fname, "wb") do |csv|
    keys = transform.keys  
    csv << keys  
    arr.each { |h| csv << keys.map { |k| transform[k].call(h) } }
  end  
end  
arr = [{:employee_id=>"001", :first_name=>"John", :last_name=>"Dee",
        :date_of_birth=>"10/10/1983", :salary=>"100000", :bonus=>"50000" },
       {:employee_id=>"002", :first_name=>"Alex", :last_name=>"Peck",
        :date_of_birth=>"11/01/1988", :salary=>"120000", :bonus=>"70000" }]
FName = 'temp.csv'
keys = arr.first.keys
  #=> [:employee_id, :first_name, :last_name, :date_of_birth, :salary, :bonus] 
transform = keys.each_with_object({}) { |k,g| g[k] = ->(h) { h[k] } }
  #=> {:employee_id=>#<Proc:0x00005bd270a0e710@(irb):451 (lambda)>,
  #    :first_name=>#<Proc:0x00005bd270a13260@(irb):451 (lambda)>,
  #    ...
  #    :bonus=>#<Proc:0x00005bd270a19cc8@(irb):451 (lambda)>} 
construct_csv(FName, arr, transform)
puts File.read(FName)
employee_id,first_name,last_name,date_of_birth,salary,bonus
001,John,Dee,10/10/1983,100000,50000
002,Alex,Peck,11/01/1988,120000,70000
col_order = [:last_name, :first_name, :employee_id, :salary, :bonus,
             :date_of_birth]
keys = arr.first.keys
order_map = col_order.each_with_object({}) { |k,h| h[k] = keys.index(k) }
  #=> {:last_name=>2, :first_name=>1, :employee_id=>0, :salary=>4,
  #    :bonus=>5, :date_of_birth=>3} 
transform = col_order.each_with_object({}) { |k,g|
  g[k] = ->(h) { h[keys[order_map[k]]] } }
  #=> {:last_name=>#<Proc:0x00005bd270f8e5a0@(irb):511 (lambda)>,
  #    :first_name=>#<Proc:0x00005bd270f8e550@(irb):511 (lambda)>,
  #    ...
  #    :date_of_birth=>#<Proc:0x00005bd270f8e3c0@(irb):511 (lambda)>} 
construct_csv(FName, arr, transform)
puts File.read(FName)
last_name,first_name,employee_id,salary,bonus,date_of_birth
Dee,John,001,100000,50000,10/10/1983
Peck,Alex,002,120000,70000,11/01/1988
keymap = { :FirstName=>:first_name, :LastName=>:last_name, :ID=>:employee_id,
           :Salary=>:salary, :Bonus=>:bonus } 
transform = keymap.each_with_object({}) { |(new,old),g| g[new] = ->(h) { h[old] } }
  #=> {:FirstName=>#<Proc:0x00005bd270d50298@(irb):391 (lambda)>,
  #    :LastName=>#<Proc:0x00005bd270d50220@(irb):391 (lambda)>,
  #    ...
  #    :Bonus=>#<Proc:0x00005bd270d830f8@(irb):391 (lambda)>} 
construct_csv(FName, arr, transform)
puts File.read(FName)
FirstName,LastName,ID,Salary,Bonus
John,Dee,001,100000,50000
Alex,Peck,002,120000,70000
keys_to_remove = [:first_name, :last_name]
keys_to_add = [:full_name, :compensation]
keys = arr.first.keys + keys_to_add - keys_to_remove
  #=> [:employee_id, :date_of_birth, :salary, :bonus, :full_name,
  #    :compensation] 
transform = keys.each_with_object({}) do |k,h|
  h[k] =
  case k
  when :full_name
    ->(h) { h[:first_name] + " " + h[:last_name] }
  when :compensation
    ->(h) { h[:salary].to_i + h[:bonus].to_i }
  else
    ->(h) { h[k] }
  end
end
  #=> {:employee_id=>#<Proc:0x00005bd271001000@(irb):501 (lambda)>,
  #    :date_of_birth=>#<Proc:0x00005bd271000f88@(irb):501 (lambda)>,
  #    :salary=>#<Proc:0x00005bd271000f10@(irb):501 (lambda)>,
  #    :bonus=>#<Proc:0x00005bd271000ec0@(irb):501 (lambda)>,
  #    :full_name=>#<Proc:0x00005bd271000e20@(irb):497 (lambda)>,
  #    :compensation=>#<Proc:0x00005bd271000dd0@(irb):499 (lambda)>} 
construct_csv(FName, arr, transform)
puts File.read(FName)
employee_id,date_of_birth,salary,bonus,full_name,compensation
001,10/10/1983,100000,50000,John Dee,150000
002,11/01/1988,120000,70000,Alex Peck,190000