Ruby Rails - 构建嵌套对象

时间:2017-05-18 06:47:50

标签: ruby-on-rails json ruby database

使用我当前的项目,我收到一个大的JSON文件,我正在解析并存储到我的数据库中。问题是我觉得我正在以非常低效的方式构建我的数据库。

JSON示例:

{
    first_name: "John",
    records: {
     ids: [110, 725, 2250],
     count: [1, 1, 6]
      },
    items: {
        top: {
            title: "My top",
            values: {  value: [51, 50, 70] }
        },
        middle: {
            title: "Middle Stuff",
            values: { value: [51] }
        },
    },
    values: {
        health: 100,
        strength: 250,
        mana: 50
    }
}

正如您所看到的,JSON相当复杂,具有嵌套的对象。

在构建它时,我从主对象(user)开始,然后慢慢开始添加更多对象。 Values非常简单,因此我将其添加为另一个表格,并仅提及user_id

然后我做records,这有点复杂,但有效。但是,我非常担心最嵌套的部分,可能是5个以上的物体。我觉得我不应该有一个简单值的整列行。

改善这一点的最佳方法是什么?我应该以某种方式处理数据并以不同方式存储它吗?

感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

// JSON回复

{
    "name": "John Smith",
    ...
    "progression": {
        "levels": [{
            "name": "Level 1",
            "bosses": [
            {
                "name": "Boss 1",
                "difficultyCompleted": "Hard"
            },
            {
                "name": "Boss 2",
                "difficultyCompleted": "Hard"
            }]
        },{
            "name": "Level 2",
            "bosses": [
            {
                "name": "Boss 3",
                "difficultyCompleted": "Normal"
            },
            {
                "name": "Boss 4",
                "difficultyCompleted": "Easy"
            }]
        }
    }
}

在此示例JSON中,用户已完成每个boss的几个层。我最初想要做的是创建模型和表格,但这似乎不仅在记忆中会浪费,而且还需要更长时间来获取Boss 4的当前进度。

示例:

User has_one Progression. 
Progression has_one Levels. 
Levels has_many Dungeons. 
Dungeons has_many bosses.

我所做的是尝试将bosses压缩为单个字段,并在运行时转换JSON。

所以,我的结构就是这样。

User has_one Progression.
Progression has_many Dungeons.

型号: // Progression.rb

class Progression < ApplicationRecord

    has_many :dungeons

    def self.initialize(params={})
        params = params['levels']

        prog = Progression.new()

        params.each do |dungeon|
            prog.dungeons.append( Dungeon.initialize( dungeon ) )
        end

        return prog
    end
end

// Dungeon.rb

class Dungeon < ApplicationRecord
    belongs_to :progression

    def self.initialize(params={})
        Dungeon.new(params.reject { |k| !Dungeon.attribute_method?(k) }) # Used to ignore any unused parameters that don't exist on the model.
    end

    # To convert `bosses` from JSON into a hash for easy use.
    def get_bosses
        JSON.parse bosses.gsub( '=>', ':' )
    end
end

迁移: // xxxxxx_create_progression.rb

class CreateProgression < ActiveRecord::Migration[5.0]
  def change
    create_table :progressions do |t|
        t.integer :character_id
    end

    create_table :dungeons do |t|
        t.integer :character_id
        t.integer :progression_id

        t.string :name
        t.text :bosses
    end

    add_index :progressions, :character_id
    add_index :dungeons, :progression_id
end
end

现在,当用户更新以获取其进展时,我可以设置他们的进展。

// users_controller.rb

def update_progression
    progression = ... fetched from the response

    @user.progression = Progression.initialize(progression)
end

之后全部保存给用户,您现在可以通过以下方式获取进度:

<% user.progression.dungeons.each do |dungeon| %>
    <%= dungeon.name %>
<% end %>

这个解决方案似乎是一个不错的组合,但我有点担心解析JSON。它可能会变得太多,但我必须继续观察它。任何其他想法或改进都将大大改变。