Rails - 在特定类别下查找模型

时间:2012-10-30 12:45:36

标签: ruby-on-rails ruby

我有一个Business模型:belongs_to Category

类别的示例层次结构:

    • 餐馆
      • 寿司
      • 披萨
      • 中国
      • 意大利

我对acts_as_tree层次结构使用Category

如何找到餐馆类别下的所有Businesses

3 个答案:

答案 0 :(得分:2)

如果您希望获得树状层次结构中节点的所有后代,您有两个选择:

  1. 使用经典acts_as_tree,预加载所选类别,开始查询的级联来检索所有的孩子,孙子等,直到你得到的只是叶(节点没有进一步chidren)。这种方法听起来很不错。

  2. 使用更高级的树表示,如嵌套集或闭包树。在这些表示下,您只需一个查询即可获取特定节点的所有后代。

  3. 然后,您可以在“企业”中获取收集的类别和查询:

    Business.where(:category => categories)
    

    (技术说明:嵌套设置)

    在一组嵌套的表示,每个节点有两个指标,以下列方式分配:想象,每个节点有两个窗口,东,西一个房子,树就像是一个分叉的道路,所有的孩子都比较或少于他们父母的北方。所以你从根屋的东边开始,在你遇到的窗户上放一个序号。你永远不会越过任何道路,你只能绕过没有通往北方的道路的房屋。最后,你将再次进入根屋,并在西窗口放一个数字。

    分配的号码将具有以下属性:

    • 所有东窗都有偶数,所有西窗都有奇数(假设你从0开始)
    • 每个房子的三角洲(西部和东部之间的差异)总是1 +后代房屋的数量
    • 任何房屋H的所有后代房屋都会将其东西方数字严格包含在H自己的数字之间
    • 反之亦然,所有数字严格包含在H数字之间的房屋实际上都是H
    • 的后代
    • 如果两个房子不是祖先另一个(因此一个的nombers是由对方的之间)然后将它们完全分离中的一个,也就是一个房子的两个数字是严格比其他的两个数字以下。

    因此,虽然在树中插入一个新元素是昂贵的(它需要更新一些索引),检索整个下降(所有子孙,......)非常容易,只需取“其节点”东部“和”西部“数字在您选择的类别的东部和西部之间。你可以稍微做得更好,但这并不重要。

    https://github.com/collectiveidea/awesome_nested_set这样的图书馆将为您管理所有这些内容,您只需拨打

    categories = @category.self_and_descendants.to_a
    

    (技术说明:关闭树)

    此方法需要一个附件表,您可以在其中存储child->parent关系的传递闭包(请参阅http://en.wikipedia.org/wiki/Reflexive_transitive_closure#P_closures_of_binary_relations

    该表将包含所有对祖先后代,因此您可以以智能方式与该表连接,以获得几乎任何层次结构的切片。

    同样,像https://github.com/mceachen/closure_tree这样的图书馆将为您完成艰苦的工作,您将能够做到

    categories = @category.self_and_descendants.to_a
    

答案 1 :(得分:0)

category = Category.find_by_name("Restaurants")

然后是商业

category.business

如果你想要孩子(寿司,披萨,中国......)那么

category.childrens

要查找所有类别,请在category.rb

中添加以下方法
  def all_children
    all = []
    self.children.each do |category|
      all << category
      root_children = category.all_children.flatten
      all << root_children unless root_children.empty?
    end
    return all.flatten
  end

然后使用

@category.all_children

EDITED 查找餐厅类别和餐厅所有子类别的商家。

Business.where("category_id = ? OR category_id in (?)", category.id, category.all_children.map(&:id))

答案 2 :(得分:0)

你能做的事情不仅仅是:

Category.find_by_name("Restaurants").businesses

修改

没有意识到你想在餐馆的子类别中做生意,呃。

对于多层次的层次结构,您首先需要获取所有类别,然后遍历每个类别,查找业务,然后将它们连接在一起

class Company < ActiveRecord::Base

  ...

  def all_children
    all = []
    self.children.each do |c|
      all << c
      root_cs = c.all_children.flatten
      all << root_cs unless root_cs.empty?
    end
    return all.flatten
  end
end

然后你可以打电话:

root_category = Category.find_by_name("Restaurants")
categories = root_category.all_children
businesses = categories.map{ |c| c.businesses }.flatten

那应该会给你一份商家清单。虽然这看起来不太好,但我觉得应该有更优化的方式。

希望无论如何它应该给你一些思考的食物。