如何在 Jbuilder 和 Normalizr 之间展平数据

Posted

技术标签:

【中文标题】如何在 Jbuilder 和 Normalizr 之间展平数据【英文标题】:How to flatten data between Jbuilder and Normalizr 【发布时间】:2019-11-19 03:22:40 【问题描述】:

我正在开发一个带有 Rails API 的小型 Vue 项目,但在找出标准化数据的最佳方法时遇到了问题。我在后端使用 Jbuilder 并希望展平/规范化通过的数据,以便更容易在前端访问,我担心我只是不太“了解”如何让 Normalizr 正常工作。

目前对于 jbuilder,我有一些与用户相关的东西,我最终希望将它们存储在 Vuex 中。

get_current_user.json.jbuilder

json.user @user

# All of user's lists and associated categories and items
json.lists @user.lists do |list|
  json.(list, :id, :name, :active, :user_id)
  json.categories list.categories do |category|
    json.(category, :id, :name, :user_id, :created_at, :updated_at, :list_id)
    json.items category.items do |item|
      json.(item, :id, :name, :website, :price, :information, :notes, :category_id, :quantity)
    end
  end
end

# User's total hiking miles
json.total_m @user.m_by_month

# User's upcoming trips properties
json.upcoming_trips @user.upcoming_trips do |trip|
  json.(trip, :id, :name, :start_date, :end_date, :data_id, :list_id)

  # User's todo items
  json.todos trip.todo_items.sort_by |t| t[:position] do |todo|
    json.(todo, :id, :title, :completed, :position, :upcoming_trip_id, :user_id)
  end

  # User's shopping list items
  json.shopping_list_items trip.shopping_list_items.sort_by |s| s[:position] do |item|
    json.(item, :id, :title, :completed, :position, :quantity, :upcoming_trip_id, :user_id)
  end

  # User's trip details
  json.trip_details hike.trip_details.order(updated_at: :desc) do |detail|
    json.(detail, :id, :trip_type, :label, :url, :upcoming_trip_id)
  end

end

那么在前端,在规范化之前,用户对象本质上是:

- user (Object)
    - packs (Array)
        - categories (Array)
            - items (Array)
    - total_m (Array)
    - upcoming_trips (Array)
        - shopping_list_items (Array)
        - todos (Array)
        - trip_details (Array)
    - user (Object)

schema.js

import  schema  from 'normalizr';

// Define user schema
export const userSchema = new schema.Entity('user');

export const itemSchema = new schema.Entity('items', 
  user: userSchema,
);

export const listSchema = new schema.Entity('lists', 
  user: userSchema,
  items: [itemSchema],
);

// Define category schema
export const categorySchema = new schema.Entity('categories', 
  user: userSchema,
  packs: [listSchema],
);

// Define upcoming trip schema
export const upcomingTripSchema = new schema.Entity('upcomingTrips', 
  user: userSchema,
  categories: [categorySchema],
);

拨打const normalizedUser = normalize(user, userSchema)后,我会收到如下信息:


  - entities (Object)
      - user (Object)
          - undefined (Object)
              - lists (Array)
              - total_m (Array)
              - upcoming_trips (Array)
              - user (Object)
  - result: undefined

好处是因为我可以控制前端和后端,所以我可以随意修改它。有没有人有什么建议?非常感谢您的帮助!

【问题讨论】:

归一化和展平真的是逆运算吗?您希望看到什么 JSON 输出?什么是关系模式(尽管可以从 JBuilder 代码中推断出来)? 【参考方案1】:

感谢您提出这个有趣的问题。如果是我,我会使用后端 ActiveRecord 查询和 JBuilder 的强大功能从 API 中生成我想要使用的 JSON。没有必要使用normalizr 作为二级过滤器。

让我担心的一件事是让 normalizr 正常工作所必需的模式重复。您在 Rails 中有模式,然后在 JS 中有另一个模式。改变一个需要改变另一个。让它们保持一致会产生集成问题。

因此,这不是一个完整的答案,而是一个问题和建议。什么是 normalizr 不能用 ARel 和 JBuilder 完成的?有了 Rails 架构和目标 JSON 的样本,有人可能会给你 ARel/JBuilder 来生成 JSON。

【讨论】:

以上是关于如何在 Jbuilder 和 Normalizr 之间展平数据的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Normalizr 定义递归模型的模式

如何使用 normalizr 规范化来自 JSON 的数据?

如何在 Jbuilder 中使用带有 Gon gem 的 Rails 助手?

如何使用“normalizr”规范化这个简单的 API 响应?

如何添加/删除使用 normalizr 生成的 redux 存储?

在 normalizr 中重命名结果属性