【问题标题】:How to generate optgroup in rails with Mongoid?如何使用 Mongoid 在 Rails 中生成 optgroup?
【发布时间】:2013-04-24 15:18:26
【问题描述】:

使用 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">]}

【问题讨论】:

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


    【解决方案1】:

    这里有几件事是错误的。

    1. 您似乎将 Enumerable#group_by 与数据库 GROUP BY 运算符混淆了。
    2. 您认为资源类型的名称来自哪里?它似乎不在资源中。

    看起来资源类型的名称在不同的集合中,您必须将 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]] }]
    

    【讨论】:

      【解决方案2】:

      以下是 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】:

        Old Pro 提到的方法很棒,但比预期的要长一点。我花了一些时间研究grouped_collection_select helper docs 中给出的示例,要点是:“为了保持简单和面向对象的方式,您必须从 ResourceType(一个)遍历到 Resource(很多)而不是相反” .另一种方式会令人困惑,因为我们将处理没有关系的自定义嵌套数组,而不是 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 的选项。

        希望它也能帮助其他人。

        【讨论】:

          【解决方案4】:

          我假设您想按 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>]]
            ]
            
          • last 方法调用在步骤 1 中返回的数组的每一行返回一个 Resource 对象数组。

          • 对第 1 步中返回的数组的每一行的first 方法调用返回资源类型名称。
          • 对第 2 步返回的数组的每一行的 idname 方法调用返回资源对象的 ID 和名称。

          【讨论】:

            猜你喜欢
            • 2014-01-02
            • 1970-01-01
            • 1970-01-01
            • 2011-09-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-07-02
            相关资源
            最近更新 更多