使用许多基于关联的限制对分页记录进行排序/分组

时间:2011-10-10 12:48:32

标签: ruby-on-rails ruby-on-rails-3 activerecord will-paginate nested-sets

我正在开发一个充当场所目录的应用程序,并且(目前但可能并非总是)允许根据1个城市,1个社区和1个类别过滤特定企业的场所。类别可以嵌套,因此它们具有parent_id。通过查看下面的模型代码可以理解这些关联(一切都相当简单)。到目前为止,一切都在顺利进行,但还有一个障碍。

首先,一些会影响答案的重要说明。

1。我正在使用will_paginate对场地关联进行分页。话虽这么说,我不能在阵列上分页。好吧,我可以,但性能将是一个问题。

2. 我使用Tag模型作为商家及其相关类别之间的链接对象。目前,该界面仅设置为允许将一个类别附加到任何给定的业务,并且必须至少附加一个。我计划稍后扩展面向公众的页面的界面以允许按多个类别进行过滤,因此除非有更好,更好的方式完成,否则无法对应用程序结构的这一部分进行更改此

3。 可能(希望)存在的可能解决方案是Arel中的表连接别名或允许类别自行加入的范围以获取家长。目前,如果解决方案假设嵌套不超过1级,我会觉得可以接受。不过,这种牺牲是最后的手段,因为它会对我希望将来推出的功能产生阻碍。

4。与最后一点相关,我看了will_paginate/array,但被他们的免责声明吓坏了(“如果你知道你在做什么,真的需要分页数组,明确要求此功能“)。记住我在尝试推出自己的分页插件时遇到的性能噩梦,我想避免这种情况,除非有人能够充分向我解释这种解决方案的性能后果。

5. 这个网站需要能够受到重创。现在,所有内容都被缓存,数据库非缓存命中数相对较少。 必须保持这种状态。

现在,我想提出的问题。

背景:一些面向公众的视图的设计规范要求当前城市的所有场地都显示在列表中并按父类别分组(不显示任何子类别,但所有企业标签属于子类别的场所也应该与标签属于父母的场所分组。然后按父类别对这些场地进行分类,然后根据场地所属的业务名称进行排序。这需要是一个平坦的关联,然后将其输入will_paginate。这个场所的ActiveRecord查询,我将在下文中称为@venues,然后被转储到JSON中,缓存并呈现给页面。

问题:如何使用指定的分组/排序构建@venues,以便根据此界面的规范对这些场地进行适当的分页和显示?

应用/模型/ business.rb

# Fields: id, name, description, keywords, ...
class Business < ActiveRecord::Base
  has_many :tags, :dependent => :destroy
  has_many :categories, :through => :tags

  has_many :venues, :dependent => :destroy

  has_many :cities, :through => :venues
  has_many :neighborhoods, :through => :venues
end

应用/模型/ venue.rb

# Fields: id, business_id, city_id, neighborhood_id, ...
class Venue < ActiveRecord::Base
  belongs_to :business
  belongs_to :city
  belongs_to :neighborhood
end

应用/模型/ tag.rb

# Fields: id, category_id, business_id, ...
class Tag < ActiveRecord::Base
  belongs_to :business
  belongs_to :category
  belongs_to :venue
end

应用/模型/ category.rb

# Fields: id, parent_id, name, description, ...
class Category < ActiveRecord::Base
  has_many :tags, :dependent => :destroy
end

应用/模型/ city.rb

# Fields: id, name, description, ...
class City < ActiveRecord::Base
  has_many :neighborhoods, :dependent => :destroy
  has_many :venues
end

应用/模型/ neighborhood.rb

# Fields: id, city_id, name, description
class Neighborhood < ActiveRecord::Base
  belongs_to :city
  has_many :venues
  has_many :businesses, :through => :venues
end

这是一个很难解释的问题,如果需要,我可以提供更多信息。

P.S。将Rails 3.0.9用于MySQL的此应用程序。

P.S.S。我也对基于多个嵌套关联字段的可能值简化这种过滤的模式或宝石感兴趣。我将授予 upvote + accept + bounty 给任何人使用嵌套集模型gem(例如Awesome Nested Set)以这种方式进行分组/排序/分页的精确解决方案。

1 个答案:

答案 0 :(得分:3)

  

不显示任何子类别,但所有商家标签属于子类别的场所也应该与标签属于父母的场所分组。

正如Xavier在评论中所说,你应该使用嵌套集模型。我正在使用这个:

https://github.com/collectiveidea/awesome_nested_set

这使我能够照常分页和排序:

module Category
  extend ActiveSupport::Concern
  included do
    belongs_to :category
    scope :sorted, includes(:category).order("categories.lft, #{table_name}.position")
  end

  module ClassMethods
    def tree(category=nil)
      return scoped unless category
      scoped.includes(:category).where([
        "categories.lft BETWEEN ? AND ?",category.lft, category.rgt
      ])
    end
  end # ClassMethods
end

#then with some category
@animals = Animal.tree(@mamal_category)

它将在一个sql调用中获取所有食草动物,食肉动物,杂食动物等等和子子类别,并且它可以轻松分类,可排序,因为它是一个范围。

另见:get all products of category and child categories (rails, awesome_nested_set)