2011-12-23 3 views
1

У меня есть набор категорий, относящихся к набору категорий. Эти категории сами могут иметь сочетание категорий (self-referential), а также вопросы. модели и их отношения определяются & визуализируется следующим образом:Модель has_many И has_many: через в одном?

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-операторов (см. Ниже пример).

Адрес КатегорияSet.find (1) .categories находит только прямые категории потомков категории. Кроме того, Category.find (id) .questions возвращает только вопросы для этой категории.

Я попытался переписать метод . по категориям, но это не кажется очень рельс-отношениями, и должен быть лучший способ сделать это? Ало это означает, что я не могу сделать CategorySet.includes (: вопросы) .all синтаксис стиль, который значительно снижает нагрузку на сервер базы данных

ответ

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 

Обратитесь к документации 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 

Теперь вы можете получить вопросы для категории, установленной в

+1

Почему этот ответ не был принят, это отличный ответ. – Yule

+0

Прошу прощения, кажется, я дал вам достойный голос, но забыл отметить его как принятый. Я реализовал решение, основанное на вышеизложенном, и оно отлично поработало. Благодаря! –

 Смежные вопросы

  • Нет связанных вопросов^_^