在Rails ActiveRecord Query上创建一个哈希数组的嵌套哈希



我使用的是rails 7,我需要创建这个数据结构。

"Tree"给定产品的可用选项组合的结构。

{
"option": "color",
"values": {
"red": {
"option": "size",
"values": {
"S": {
"option": "material",
"values": {
"cotton": {
"sku": "shirt-red-s-cotton"
}
},
},
"M": { ... },
"L": { ... },
}
},
"green": { ... },
"blue": { ... }
}
}

我有下一个模式:


ActiveRecord::Schema[7.0].define(version: 2022_11_04_214231) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "items", force: :cascade do |t|
t.bigint "product_id", null: false
t.json "p_options"
t.string "sku"
t.integer "stock"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["product_id"], name: "index_items_on_product_id"
t.index ["sku"], name: "index_items_on_sku", unique: true
end
create_table "product_option_lists", force: :cascade do |t|
t.bigint "product_id", null: false
t.bigint "product_option_id", null: false
t.string "option"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["product_id"], name: "index_product_option_lists_on_product_id"
t.index ["product_option_id"], name: "index_product_option_lists_on_product_option_id"
end
create_table "product_options", force: :cascade do |t|
t.string "option"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["option"], name: "index_product_options_on_option", unique: true
end
create_table "products", force: :cascade do |t|
t.string "name"
t.boolean "active"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["name"], name: "index_products_on_name", unique: true
end
add_foreign_key "items", "products"
add_foreign_key "product_option_lists", "product_options"
add_foreign_key "product_option_lists", "products"
end

我相信所有需要的信息,开始使这个数据结构可以通过ActiveRecord获取:

Item.where(product_id: <some_id>)

# or maybe mapping it to get only the options of the product

Item.where(product_id: <some_id>).map{ |item| item.p_options }

第二个查询返回如下值:(根据我使用的种子数据)

[{ "Size" => "S", "Color"=>"Red"   , "Material"=>"Cotton"},
{ "Size" => "S", "Color"=>"Green" , "Material"=>"Silk"},
-----------
{ "Size" => "XL", "Color" => "Blue", "Material"=> "Cotton"}]

我也认为这可以通过递归每个键的可能值来完成。但是我仍然不理解哈希结构的递归。


也许我已经做的这个端点是有用的。它返回给定产品的数据结构。

[
{ "option": "color", "values": ["Red","Green", "Blue"]},
{ "option": "size", "values": ["S", "M", "L"]},
...
]

我已经创建了产品选项来处理所有可用的递归选项

这是我用递归 创建的一个演示
create_table "product_options", force: :cascade do |t|
t.string "option_label"
t.string "option_text"
t.string "value_label"
t.bigint "product_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.bigint "parent_id"
t.index ["parent_id"], name: "index_product_options_on_parent_id"
end
create_table "products", force: :cascade do |t|
t.string "name"
t.boolean "active"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["name"], name: "index_products_on_name", unique: true
end
add_foreign_key "product_options", "product_options", column: "parent_id"
add_foreign_key "product_options", "products"

class ProductOption < ApplicationRecord
belongs_to :parent, optional: true, class_name: 'ProductOption'
has_many :options, class_name: 'ProductOption', foreign_key: :parent_id, dependent: :destroy  
end
def index
@product_options = ProductOption.first
end

index.html.erb

<%= @product_options.option_label %>:<%= @product_options.option_text %></br>
<%= render partial:'partial', locals:{ option: @product_options.options } %>

_partial.html.erb

<% option.each_with_index do |single, index| %>
<%= "#{single.option_label}:#{single.option_text}" if single.option_label.present? %> <br>
<%= "#{single.value_label}:" %> <br>
<%= render partial: 'partial', locals: {option: single.options}  %><br>
<% end%>

种子数据添加:https://gist.github.com/hemangini-gohel/c1fff10f60f51390c60de73fd3d1b31b