第 6 部分 - 关系

这个应用程序中还有一个功能 - 列表。如果您点击提醒面板左侧的按钮,将打开一个侧边栏,显示应用程序中的不同列表。

Failing

但现在,我们在控制台中只看到一个错误,因为应用程序期望从 /api/lists 获取列表。让我们模拟这个端点。

首先,我们将在服务器顶部的 list 模型中定义一个新模型。

models: {
  list: Model,
  reminder: Model,
}

我们还将为 GET 到 /api/lists 添加一个新的路由处理程序,该处理程序返回所有列表。

this.get("/api/lists", (schema, request) => {
  return schema.lists.all()
})

Mirage 现在响应 200,但没有列表。让我们在 seeds() 中创建一些列表。

seeds(server) {
  server.create("reminder", { text: "Walk the dog" });
  server.create("reminder", { text: "Take out the trash" });
  server.create("reminder", { text: "Work out" });

  server.create("list", { name: "Home" });
  server.create("list", { name: "Work" });
}

现在当我们打开侧边栏时,我们看到我们的两个新列表“主页”和“工作”被渲染。

尝试点击一个列表。您将看到一个错误,因为我们的应用程序期望另一个 API 端点存在:/api/lists/1/reminders。这就是它如何获取特定列表的提醒。让我们看看如何模拟它。

在 Mirage 中模拟处理关系数据的端点的最简单方法是使用 关联。我们将从使用 Mirage 的关联助手来模拟此数据开始。

在这个应用程序中,列表和提醒之间存在一对多关系(一个列表可以有多个提醒),因此我们将使用 hasManybelongsTo 助手来定义这种关系。

导入助手并更新您的模型以定义这种关系。

import { createServer, Model, hasMany, belongsTo } from "miragejs"

export default function () {
  createServer({
    models: {
      list: Model.extend({
        reminders: hasMany(),
      }),

      reminder: Model.extend({
        list: belongsTo(),
      }),
    },

    // rest of server
  })
}

现在 Mirage 知道 list.remindersreminder.list 属性是关系,因此我们可以在路由处理程序中开始使用它们。

让我们使用新的关系模拟 /api/lists/:id/reminders。此端点应查找相应的列表,并返回属于该列表的所有提醒。

以下是代码。

this.get("/api/lists/:id/reminders", (schema, request) => {
  let listId = request.params.id
  let list = schema.lists.find(listId)

  return list.reminders
})

我们使用 :id 的动态片段,它对应于我们点击的列表。然后我们使用该 ID 在 Mirage 的数据层中查找相应的列表。最后,我们返回与该列表相关的提醒。

将此路由处理程序复制到 Mirage 服务器定义中,并尝试点击每个列表。您应该不再看到错误。但您也看不到任何提醒。这是因为我们创建的提醒还没有与任何列表相关联 - 我们只是单独创建了它们。

要为特定列表创建提醒,我们可以使用新的关系。

seeds(server) {
  // Unassociated reminders
  server.create("reminder", { text: "Walk the dog" });
  server.create("reminder", { text: "Take out the trash" });
  server.create("reminder", { text: "Work out" });

  let homeList = server.create("list", { name: "Home" });
  server.create("reminder", { list: homeList, text: "Do taxes" });

  let workList = server.create("list", { name: "Work" });
  server.create("reminder", { list: workList, text: "Visit bank" });
}

现在,点击“主页”应显示“缴税”提醒。如果您点击“全部”,应用程序将点击 /api/reminders 端点,该端点仍将返回系统中的所有提醒 - 那些与列表相关的和那些独立的。

最后,尝试在 UI 中为特定列表制作新的提醒。点击“工作”,然后添加一个提醒“回复吉尔”。如果您点击应用程序周围,您将看到它已正确地与“工作”列表相关联。(它显示在“工作”和“全部”中,但不显示在“主页”中)。

这是因为我们的 UI 在我们在列表中创建提醒时已经发送了 { listId }。要查看这一点,让我们在现有的 POST 路由处理程序中添加一个日志来检查来自请求的 attrs。

this.post("/api/reminders", (schema, request) => {
  let attrs = JSON.parse(request.requestBody)
  console.log(attrs)

  return schema.reminders.create(attrs)
})

创建未关联的任务时,attrs 为 { text: "New todo" },但关联的任务有类似 { text: "Respond to Jill", listId: "2" } 的 attrs。

当我们定义关系时,Mirage 在我们的模型上设置了称为外键的特殊属性。这些属性是它跟踪哪些模型相互关联的方式。设置类似 listIdreminderIds: [] 的外键就足以更新关系并使其反映在所有 Mirage 路由处理程序中。

因此,我们不必更新 POST 处理程序以适应 UI 的列表功能,因为 listId 已经传递到 reminders.create() 中。

Mirage 的关联助手足够灵活,可以模拟几乎任何数据场景,这使得您在模拟处理关系的端点时更容易。

要点

  • Mirage 允许您定义和访问关系数据。
  • 使用 belongsTohasMany 助手在您的模型上定义命名关系。
  • 在路由处理程序中使用关系以返回与其他模型关联的模型或集合。
  • Mirage 使用简单的外键来跟踪关系数据。