2016-01-22 34 views
0

我有一个散列数组。这里是典型值的小样本:供应红宝石阵列选择一个动态块

[{"id"=>1, 
    "context"=>"r178", 
    "asset"=>"Art Schools Hub", 
    "campaign"=>"Fashion Careers", 
    "contact_email"=>"[email protected]", 
    "notes"=>"", 
    "user_first_name"=>"Agustin", 
    "user_last_name"=>"Welch", 
    "status"=>"Completed", 
    "date_collected"=>"01/22/16"}, 
{"id"=>4, 
    "context"=>"r178", 
    "asset"=>"Art Schools Hub", 
    "campaign"=>"Graphic Design Careers", 
    "contact_email"=>"[email protected]", 
    "notes"=>"", 
    "user_first_name"=>"Agustin", 
    "user_last_name"=>"Welch", 
    "status"=>"In Progress", 
    "date_collected"=>"01/22/16"}, 
{"id"=>15, 
    "context"=>"r178", 
    "asset"=>"Art Schools Hub", 
    "campaign"=>"Art Education", 
    "contact_email"=>"[email protected]", 
    "notes"=>"", 
    "user_first_name"=>"Jermaine", 
    "user_last_name"=>"Wilkinson", 
    "status"=>"Open", 
    "date_collected"=>"01/22/16"}] 

我知道做一个选择是这样的:

results = @network.select { |x| x["campaign"] == "Art Education" && x["status"] == "Open" } 

滤光器阵列返回哈希数组,其中所选择的按键具有搜索到的值。

但是,用户必须能够基于任何或所有具有用户提交的值的键过滤此数组。

虽然我可以替代从表单的PARAMS的值代入这样的块:

results = @network.select { |x| x[params[1]["column"]] == params[1]["search"] && x[params[2]["column"]] == params[2]["search"] } 

每一选择的逻辑可以不同。可以有多达10个不同的条件,列值和搜索值的形式为params。

我需要一种方法来根据用户提交的条件动态地在选择的块部分中创建表达式。

不幸的是,我试图为块构造表达式的每种方式都会导致无法通过select进行评估的字符串值。

我已经为此工作了好几天了,所以如果有人能给我一个解决方案,我将非常感激。

编辑: 由于魔杖制作的优雅的解决方案,我做了如下修改,根据他的代码,允许用户散列的基于键,其搜索值与用户提交的值开始滤镜阵列,而不是等于该值:

pm = params.map { |h| {h["column"] => h["search"].downcase} }.reduce(&:merge) 

result = @network.select do |h| 
    temp = h.slice(*pm.keys) 
    new_temp = Hash.new 
    temp.each do |k,v| 
      new_temp[k]=v.downcase.slice(0..pm[k].length - 1) 
    end 
    new_temp == pm 
end 

这现在工作的很好。

+1

我认为你会更好在数据库级别过滤。这就是它的目的。 – seph

+0

用户可以提交什么样的东西? –

+0

您能否详细说明每个选择的逻辑可能不同。可能有多达10种不同的条件 - 在你的示例代码中,你使用'&&'运算符来表示条件,你是否暗示可以有'||'和这些条件的混合? –

回答

1

以下是一种可能的方法。

让我们来定义params是:

params = [{"column" => "context", "search" => "r178"}, 
      {"column" => "campaign", "search" => "Art Education"}] 

我们将它处理到@network结构上类似的元素。

pm = params.map { |h| {h["column"] => h["search"]} }.reduce(&:merge) 
#=> {"context"=>"r178", "campaign"=>"Art Education"} 

现在,我们将选择处理PARAMS散列pm存在于该钥匙,并用它来从@network阵列获得的各元素的切片,并且如果处理PARAMS散列和切片散列都相等,那么,我们有一场比赛,我们可以选择该项目。

result = @network.select {|h| h.slice(*pm.keys) == pm} 

完整代码示例中,我添加require "active_support/core_ext/hash"使得下面的程序可以运行作为用于说明的目的独立红宝石程序。在Rails代码中不需要它。

require "pp" 
require "active_support/core_ext/hash" 

@network = [{"id"=>1, "context"=>"r178", "asset"=>"Art Schools Hub", "campaign"=>"Fashion Careers", "contact_email"=>"[email protected]", "notes"=>"", "user_first_name"=>"Agustin", "user_last_name"=>"Welch", "status"=>"Completed", "date_collected"=>"01/22/16"}, 
{"id"=>4, "context"=>"r178", "asset"=>"Art Schools Hub", "campaign"=>"Graphic Design Careers", "contact_email"=>"[email protected]", "notes"=>"", "user_first_name"=>"Agustin", "user_last_name"=>"Welch", "status"=>"In Progress", "date_collected"=>"01/22/16"}, 
{"id"=>15, "context"=>"r178", "asset"=>"Art Schools Hub", "campaign"=>"Art Education", "contact_email"=>"[email protected]", "notes"=>"", "user_first_name"=>"Jermaine", "user_last_name"=>"Wilkinson", "status"=>"Open", "date_collected"=>"01/22/16"}] 

params = [{"column" => "context", "search" => "r178"}, 
      {"column" => "campaign", "search" => "Art Education"}] 

pm = params.map { |h| {h["column"] => h["search"]} }.reduce(&:merge) 
pp result = @network.select {|h| h.slice(*pm.keys) == pm} 

#=> [{"id"=>15, 
#  "context"=>"r178", 
#  "asset"=>"Art Schools Hub", 
#  ... 
#  "status"=>"Open", 
#  "date_collected"=>"01/22/16"}] 

对于澄清评价寻求,溶液可适于以及用于starts_with类型的条件。一个可以使用:

pp result = @network.select {|h| pm.keys.all?{|k| h[k].starts_with? pm[k]}} 
+0

这对于筛选等于用户提交的搜索值的值时效果很好(尽管在Rails中我似乎不需要'pp')。但是,这是另一个皱纹。他们希望价值从用户提交的角色开始,而不是平等。这可以修改以处理这个问题吗? – Doug366

+0

@ Doug366我已经更新了答案,希望它能满足您的需求。 –