【问题标题】:Rails Arel, Select from same column but multiple valuesRails Arel,从同一列中选择多个值
【发布时间】:2014-03-08 12:39:22
【问题描述】:

我有一张名为cherry_picker_cherries 的表。这些记录多态地属于一个名为Pickable 的模型。他们可以在表中为同一个pickable 有多个条目,但它总是有不同的cherry_pick_id

我的问题:我有一个名为Favorite Tree 的cherry pick 和一个名为Favorite Fruit 的单独cherry_pick。我希望能够通过多个樱桃挑选来过滤一组可挑选的东西。例如,我想查找所有最喜欢的树为cherry 和最喜欢的水果为orange 的所有可摘果。

我可以使用以下方法以糟糕的方式完成此操作:

CherryPicker::Cherry.find_by_sql("SELECT * from cherry_picker_cherries t1 JOIN cherry_picker_cherries t2 USING(pickable_id) WHERE t1.value = 'orange'AND t2.value = 'cherry'")

但是,这种方法有几个缺点。它不能处理更多的 Cherry Picks,现在只有两个。此外,结果集被转换为一个数组,但我需要返回一个 ActiveRecord 关系,以便我可以继续将方法链接到它上面。

我试图查看 AREL 是否有某种解决方案来生成与上述匹配的简单查询,但我陷入了死胡同。循环遍历参数的散列以允许您可以过滤的 2、3、4 或 X 个樱桃选择很容易。

这甚至可以在 AREL、rails 或其他任何东西中实现吗?

【问题讨论】:

  • 让我知道下面的代码是否适合您,以便我可以将其编辑为更通用 =)

标签: mysql ruby-on-rails ruby arel


【解决方案1】:

以下解决方案实际上是更大问题的一部分,但我确实设法使用您给我的点点滴滴让它工作:

def self.with_cherries(params={})
  # See also: http://stackoverflow.com/questions/21689795/rails-arel-select-from-same-column-but-multiple-values
  result = all
  if (params.keys.length > 1)
    # filtering by 2 or more cherry picks
    result = result.joins(:cherries).where("cherry_picker_cherries.pickable_type = ?", self.name)

    # Setup the complicated joins
    params.each_with_index do |cherry_pick_and_value, index|
      result = result.joins("JOIN cherry_picker_cherries t#{index} USING(pickable_id)") unless index.zero?
    end

    my_query_string = ""
    params.values.each_with_index do |k, i|
      if i.zero?
        my_query_string << "cherry_picker_cherries.value = ?"
      else
        my_query_string << " AND t#{i}.value = ?"
      end
    end
    sanitized_string = self.sanitize_sql_array([my_query_string, params.values].flatten)
    result = result.where(sanitized_string).references(:cherries)
  else
    if params.present? && (params.keys.length == 1)
      # Only filtering by a single cherry pick
      result = result.with_cherry(params.first.first, params.first.last)
    end
  end
  result
end

【讨论】:

    【解决方案2】:

    你可以试一试吗?

    CherryPicker::Cherry.joins("join cherry_picker_cherries t2 using(pickable_id)").where("cherry_picker_cherries.value = ? and t2.value = ?", 'orange', 'cherry')

    如果可行,您可以遍历您想要加入的水果,并使用递增的变量名(t3、t4.. 等)执行另一个 joins,因为 sql 查询在需要之前不会执行。

    以下是如何多次加入同一个表:

    arr = ['orange', 'cherry', 'apple']
    
    query = CherryPicker::Cherry.joins("join cherry_picker_cherries t0 using(pickable_id)")
    
    arr.drop(2).each_with_index do |e,i|
      query = query.joins("join cherry_picker_cherries t#{i+1} using(pickable_id)")
    end
    

    您也可以这样做来生成您的wheres

    如果您能提出修改建议,那就太好了,这样我就可以改进这篇文章,因为没有您的表格真的很难测试 =)

    【讨论】:

    • 酷.. 现在你能给我举个例子吗?
    猜你喜欢
    • 2011-04-03
    • 2015-09-25
    • 2012-07-03
    • 2020-07-07
    • 2012-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多