2015-06-05 135 views
0

我有这样的场景:最佳方式

class Category < ActiveRecord::Base 

    has_many  :children, :class_name => "Category", :foreign_key => "parent_id" 
    belongs_to :parent,  :class_name => "Category", :foreign_key => "parent_id" 

    def self.for_select 
    ?? DO SOMETHING ?? 
    end 

end 

而我只需要生成一个select_tag这样的选择:

Category 1 
    - Subcategory 1 
    - Subcategory 2 
    - Subcategory 3 
Category 2 
    - Subcategory 4 
    - Subcategory 5 

我怎样才能做到这一点没有强调用循环查询的数据库?

其实,我有这样的事情,但它正在执行太多的疑问:

def self.for_select 
    ret = [] 
    Category.where(parent_id: nil).each do |m| 
    ret << [m.name, m.id] 
    m.children.each { |c| ret << ["- #{c.name}", c.id] } 
    end 
    return ret 
end 
+2

您可以加载孩子,以限制数据库调用次数。 'Category.where(parent_id:nil).includes(:children)' – Santhosh

+0

@Santhosh是对的。我会将它作为“范围”添加... –

回答

1

目前尚不清楚你要出现在选择的选项是什么。在这里,我假定“类别”是所有没有父母的类别,而子类别是这些类别的直接子类别。

在您的类别类

#class methods section 
class << self 

    def select_options 
    top_level_categories = Category.where(:parent_id => nil).includes(:children) 
    top_level_categories.collect{|category| [[category.name, category.id]] + category.children.collect{|category| [" - #{category.name}, category.id]}} 
    end 

应返回

[["Category 1", 321], [" - Subcategory 1", 123], [" - Subcategory 2", 456]...etc] 

那么,在您看来,做

select_tag "foo", options_for_select(Category.select_options)  
+0

第1类和第2类不是组,然后,在您说你想要的选项中?我认为你的要求不清楚。 –

+0

@MattiaMalonni你有没有试过我建议的?它将工作,即使我在我的代码库中使用它... –

+0

o我c。我正在重写我的答案,因为这很混乱。也意识到你不能只在开始时获得Category.all –

0

试着这么做:

class Category 
    # ... 

    scope :main_categories, -> { where(parent_id: nil) } 

    def self.for_select 
    main_categories.includes(:children).each_with_object([]) do |cat, ret| 
     ret << [cat.name, cat.id] 
     ret << cat.children.map { |sub| ["- #{sub.name}", sub.id] } 
    end 
    end 
end 

希望有帮助!