防止REST中的破碎对象组合

huangapple go评论86阅读模式
英文:

Preventing broken object composition in REST

问题

我有一个Sinatra应用程序,其中有一个Project模型和一个Task模型,项目has_many任务。

这是一种组合关系,意味着没有与任务相关联的项目无法存在。

我在/projects/new上创建一个项目,然后重定向到/projects/:id/tasks/new以添加任务到项目。在后一个页面上,我:

  1. 从URL中的参数实例化新创建的项目实例
  2. 创建若干个任务
  3. 验证所有的任务
  4. 将它们添加到项目中。

问题是,如果在上述任何步骤中被打断,那么将不会添加任何任务,并且项目将保存在数据库中,但没有相关联的任务。这将在计算总任务持续时间和其他情况下导致错误。

我可以在同一页上实例化和保存这两条记录,这将解决问题。

但是,是否有一种方法可以在专用URL之间拆分ProjectTask的创建,而不会导致没有任务的项目?

英文:

I have a Sinatra app with a Project model and a Task model, and a project has_many tasks.

It's a composition type of relationship, meaning a project cannot exist without tasks associated.

I create a project on /projects/new, then redirect to /projects/:id/tasks/new to add tasks to the project. On the latter page, I:

  1. instantiate the newly-created project instance from the param in the URL
  2. create a number of tasks
  3. validate all the tasks
  4. add them to the project.

The problem is, if one gets interrupted during any of the step above, then no tasks will be added and the project will be saved in the database with no tasks associated. This will result in errors when I calculate total task duration, and in other situations.

I could instantiate and save both records on the same page, and that would solve the problem.

But, is there a way to split Project and Task creation across dedicated URLs without this resulting in childless projects?

答案1

得分: 1

我建议您在至少创建一个任务后才创建项目。您可以通过将项目详细信息保存在session中,然后从任务控制器实际创建项目来实现这一点,例如(伪代码):

# 项目控制器
def create
  session[:new_project] = <提取会话参数到PORO>
  redirect_to new_tasks_url
end

# 任务控制器
def new
  @new_project_params = session[:new_project]
  # 根据需要在视图中使用此参数
end

def create
  Project.transaction do
    project = Project.create(session[:new_project])
    project.tasks.create(task_params)
  end
end

您可以在这里查看如何在Sinatra中使用session:https://sinatrarb.com/faq.html#sessions

另一种选择是更改您的代码以允许没有任务的项目。我的直觉告诉我这可能是用户所期望的;如果他们创建了一个项目,然后没有时间创建任何任务,他们可能会认为项目已实际保存。

这将导致在计算总任务持续时间时出现错误,以及在其他情况下也会出现错误。

看起来这个特定问题似乎可以通过将总任务持续时间默认为0来解决。但再次,我不了解您的应用程序的实际目的,所以也许我是错的。

英文:

I would advise you to not create the Project until at least one Task has been created. You can do this by saving the project details in session and then actually creating the Project from the tasks controller, for example (pseudocode):

# projects controller
def create
  session[:new_project] = &lt;extract session params to PORO&gt;
  redirect_to new_tasks_url
end

# tasks controller
def new
  @new_project_params = session[:new_project]
  # use this in the view as needed
end

def create
  Project.transaction do
    project = Project.create(session[:new_project])
    project.tasks.create(task_params)
  end
end

You can see how to use session in Sinatra here: https://sinatrarb.com/faq.html#sessions

Another option is to change your code to allow Projects with no Tasks. My hunch tells me this is what users expect; if they create a project and then don't have time to create any tasks; they would maybe assume that the project would be actually saved.

> This will result in errors when I calculate total task duration, and in other situations.

It seems like this particular problem could be resolved by just defaulting total task duration to 0. But then again, I don't know the actual purpose of your application here, so maybe I'm wrong.

huangapple
  • 本文由 发表于 2023年3月9日 23:11:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/75686498.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定