
[code]

     class << self
       def category_sort
         order(small_category_id: "asc", id: "asc")
         .group_by { |w| w.small_category.name }
       end
     end
    
[/code]

上記の結果は下記のようなハッシュになります。

[code]

     small_category1 => [data1,data2,data3]
     small_category2 => [data4,data5]
     small_category3 => [data6,data7,data8]
    
[/code]

big_categoryがあるので、各big_categoryに関連するsmall_categoryをぶら下げたいと思っているのですが、どのようにプログラムを書いていいのかわかりません。

結果下記のようなイメージでデータを取りたいです。small_category1とsmall_category2はbig_category1にぶら下がっていて、small_category1とsmall_category2は各関連するデータを持っているようなイメージです。

[code]

     big_category1 => small_category1 => [data1,data2,data3]
                   => small_category2 => [data4,data5]
     big_category2 => small_category3 => [data6,data7,data8]
    
[/code]

下記のようにするとできるのですが、よりスマートなやり方があれば、ご教示いただきたいです。

[code]

    class << self
      def category_sort
        r = order(small_category_id: "asc", id: "asc")
            .group_by { |w| [w.small_category.big_category.name, w.small_category.name] }
    
        hash = Hash.new { |h,k| h[k] = {} }
        r.each do |k, v|
          hash[k[0]][k[1]] = v
        end
      end
    end
    
[/code]


CC BY-SA 3.0
2017-03-25T17:45:12.430
33535
2017-03-25T23:52:40.933
18982
question
ruby-on-rails ruby
ハッシュのネストを作りたい


一旦big_categoryで`#group_by`してから、[#map](https://docs.ruby-
lang.org/ja/latest/class/Enumerable.html#I_COLLECT)を使うことで、big_category内のデータをさらにsmall_categoryでグルーピングできます。

[code]

    def category_sort
      order(small_category_id: "asc", id: "asc")
        .group_by { |w| w.small_category.big_category.name }
        .map { |big_category,ws| [big_category, ws.group_by { |w| w.small_category.name }] }
        .to_h
    end
    
[/code]

Ruby 2.0以前であれば、[`Array#to_h`](https://docs.ruby-
lang.org/ja/latest/class/Array.html#I_TO_H)が使えないので、`to_h`の代わりに

[code]

    .each_with_object({}) {|(k,v),h| h[k] = v }
    
[/code]

などとします。

蛇足ながら、small_categoryもbig_categoryもActiveRecordのモデルなのであれば、`#includes`
などを使うことで関連カテゴリを[一括読み込み](https://railsguides.jp/active_record_querying.html#%E8%A4%87%E6%95%B0%E3%81%AE%E9%96%A2%E9%80%A3%E4%BB%98%E3%81%91%E3%82%92%E4%B8%80%E6%8B%AC%E3%81%A7%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%82%80)することで、クエリ数を抑えられます。

[code]

    def category_sort
      includes(small_category: :big_category)
        .order(small_category_id: "asc", id: "asc")
        ...
    end
    
[/code]

とか。（このメソッドの使われ方次第なので、必ずこうすべきとは言えませんが）


CC BY-SA 3.0
2017-03-25T23:52:40.933
33536
2017-03-25T23:52:40.933
30
33535
answer