1

カテゴリセットに属するカテゴリのセットがあります。これらのカテゴリ自体には、カテゴリ(自己参照)と質問が混在している場合があります。モデルとその関係は、次のように定義および視覚化されます。

class CategorySet < ActiveRecord::Base
  has_many :categories
end

class Category < ActiveRecord::Base
  belongs_to :category_set

  belongs_to :parent_category, :class_name => "Category"
  has_many :categories, :class_name => "Category", :foreign_key => "parent_category_id", dependent: :destroy

  has_many :questions, dependent: :destroy
end

class Question < ActiveRecord::Base
  belongs_to :category
end

Abbrev to CS, C and Q:

CS
  |- C
     |- Q
     |
     |- C
     |
     |- C
     |  |- Q
     |
     |- C
        |- Q
        |- Q

CategorySet.find(1).questionsに質問して、位置に関係なくツリー内のすべての質問を返すことができるようにしたいと思います。私が考えることができる唯一の方法は、多くの関数ベースの要求を使用し、SQLステートメントではおそらくやり過ぎでしょう(例については以下を参照してください)。

CategorySet.find(1).categoriesを呼び出すと、カテゴリセットの直接の子孫カテゴリのみが検索されます。また、Category.find(id).questionsは、そのカテゴリの質問のみを返します。

カテゴリの.questionsメソッドを上書きしようとしましたが、それはあまりレール関係に似ていないようで、これを行うためのより良い方法があるはずです。つまり、CategorySet.includes(:questions).allスタイルの構文を実行できないため、データベースサーバーの負荷が大幅に軽減されます。

4

1 に答える 1

3

アプローチ1

これにはawesome_nested_setを使用してください

class CategorySet < ActiveRecord::Base
  has_many :categories
  def questions
    categories.map do |c|   
      c.self_and_descendants.include(:questions).map(&:questions)
    end.flatten
  end
end

class Category < ActiveRecord::Base
  awesome_nested_set
  belongs_to :category_set
  has_many :questions
end

class Question < ActiveRecord::Base
  belongs_to :category
end

gemに必要な追加の列のリストを取得するには、 awesome_nested_setのドキュメントを参照してください。

アプローチ2

アプローチ1はすべての質問をメモリにロードし、DBベースのページネーションをサポートしていません。

各カテゴリに他のカテゴリを含めることができるため、CategorySetに個別のテーブルを維持しないようにすると、パフォーマンスが向上します。

class Category < ActiveRecord::Base
  awesome_nested_set
  has_many :questions
  # add a boolean column called category_set

  def questions
    join_sql = self_and_descendants.select(:id).to_sql
    Question.joins("JOIN (#{join_sql}) x ON x.id = questions.id")  
  end
end

class Question < ActiveRecord::Base
  belongs_to :category
  validates :category_id, :presence => true, :category_set => true
end

# lib/category_set_validator.rb
class CategorySetValidator < ActiveModel::EachValidator  
  def validate_each(object, attribute, value)  
    if record.category.present? and record.category.category_set?
      record.errors[attribute] << (options[:message] || 
                    "is pointing to a category set") 
    end
  end 
end  

これで、次のように設定されたカテゴリの質問を取得できます

cs.questions.limit(10).offset(0)
cs.questions.paginate(:page => params[:page])  # if you are using will_paginate 
于 2011-12-23T07:29:41.367 に答える