如何使用Mongoid在rails中生成optgroup?

时间:2013-04-24 15:18:27

标签: ruby-on-rails mongodb group-by mongoid

使用MongoDB时分组选项的最佳方法是什么?

当我尝试这种方法时,我正在使用Mongoid:

<%= field.select :resource_id, 
    grouped_options_for_select(Resource.all.group_by{"resource_type_id"}.map {|k,m|
    [m.first.title, m.first.id] }),:prompt => true %>

它给了我以下错误:

  

“5177e6a5359f105f89000001”的未定义方法`map':Moped :: BSON :: ObjectId

我正在寻找:

<select>
    <optgroup label="RT1">   <!-- RT1 is the name of resource type -->
        <option value="5177e6a5359f105f89000001">Res1</option>
    </optgroup>
</select>

此外,在控制台中Resource.all.group_by{"resource_type_id"}的输出是

=> {"resource_type"=>[#<Resource _id: 5177e6a5359f105f89000001, 
created_at: 2013-04-24 14:05:25 UTC, updated_at: 2013-04-24 14:54:14 UTC,
title: {"en"=>"Res1"}, slug: {"en"=>"res1"}, content: 
{"en"=>"This is the content for First Resource."},
excerpt: {"en"=>"This is the content for First Resource."}, published: true,
resource_type_id: "5177e3ba359f10d345000004">]}

虽然预期结果是

=> {"RT1"=>[#<Resource _id: 5177e6a5359f105f89000001, 
created_at: 2013-04-24 14:05:25 UTC, updated_at: 2013-04-24 14:54:14 UTC,
title: {"en"=>"Res1"}, slug: {"en"=>"res1"}, content: 
{"en"=>"This is the content for First Resource."},
excerpt: {"en"=>"This is the content for First Resource."}, published: true,
resource_type_id: "5177e3ba359f10d345000004">]}

4 个答案:

答案 0 :(得分:0)

这里有几件事是错误的。

  1. 您似乎将Enumerable#group_by与数据库GROUP BY运算符混淆。
  2. 您认为资源类型的名称来自哪里?它似乎不在资源中。
  3. 看起来资源类型的名称位于不同的集合中,您必须分别将ID映射到名称。这是Mongoid的NoSQL部分:您不能简单地加入Resource和ResourceType表。

    Resource.all.group_by { |r| r.resource_type_id }
    

    会让你入门,但哈希键将是ID,而不是名称。 (这也会同时将所有资源读入内存,这在很多情况下会出现问题,但由于你在选项列表中显示所有这些资源,我假设列表足够小就可以了。)你'然后需要获取名称映射并替换散列键。类似的东西:

    resource_names = {}
    ResourceType.each { |rt| resource_names[rt.id] = rt.name }
    resource_groups = Resource.all.group_by { |r| r.resource_type_id }
    resource_options = Hash[resource_groups.map { |k, v| [resource_names[k] || k, [v.title["en"], v.id]] }]
    

答案 1 :(得分:0)

Old Pro提到的方法很棒,但比预期的要长。我花了一些时间在grouped_collection_select helper docs中给出的例子,并且要点是:“为了保持简单和面向对象的方式,你必须从ResourceType(一个)遍历资源(很多)而不是另一个方式周围”。另一种方式会让人感到困惑,因为我们将处理与ORM对象无关的自定义嵌套数组。

因此,我所需的输出可以通过ERB中的以下Ruby(单行)代码生成:

<%= field.grouped_collection_select :resource_id, ResourceType.order_by([:name,:asc]), 
    :resources, :name, :id, :title,  :prompt => true %>

..其中:resources:name属于ResourceType,:id:title属于Resource选项。

希望它也能帮助别人。

答案 2 :(得分:0)

以下是optgroup的一个示例:

 @city_group =
                 [
                 ["Wisoncin", [["Lake Geneva", "1"], 
                 ["Elkhart Lake", "2"]]],
                 ["Michigan", [["Harbor Country", "3"], ["Traverse City", "4"]]],
                 ["Indiana", [["Bloomington", "5"], ["Valparaiso", "6"]]],
                 ["Minnesota", [["Twin Cities", 
                 "7"], ["Bloomington", "8"], ["Stillwater", 
                 "9"]]],
                 ["Florida", [["Sanibel & Captiva", "10"]]],
                 ["Illinois", [["Chicago", "11"], 
                 ["Galena", "12"]]],
                 ]

并在您的观看中添加:

<%= select_tag(:brand_id, grouped_options_for_select(@city_group, selected_key = "11", prompt = nil)) %>

希望它有所帮助!请享用!

答案 3 :(得分:-1)

我假设您要按resource_type而不是resource_type_id对选项进行分组。

f.grouped_collection_select :resource_id, 
                            Resource.all.group_by(:resource_type).to_a, 
                            :last, :first, :id, :name

<强>解释

  • Resource.all.group_by(:resource_type).to_a返回一个数组数组。

    [
      [ "R1", [<Resource _id 51xx0001>, <Resource _id 51xx0002>]],
      [ "R2", [<Resource _id 51xx0003>, <Resource _id 51xx0004>]]
    ]
    
  • 在步骤1中返回的数组的每一行上的last方法调用返回一个Resource对象数组。

  • 对步骤1中返回的数组的每一行进行first方法调用,返回资源类型名称。
  • 在步骤2中返回的数组的每一行上的idname方法调用返回资源对象的id和名称。