英文:
Preventing broken object composition in REST
问题
我有一个Sinatra应用程序,其中有一个Project
模型和一个Task
模型,项目has_many
任务。
这是一种组合关系,意味着没有与任务相关联的项目无法存在。
我在/projects/new
上创建一个项目,然后重定向到/projects/:id/tasks/new
以添加任务到项目。在后一个页面上,我:
- 从URL中的参数实例化新创建的项目实例
- 创建若干个任务
- 验证所有的任务
- 将它们添加到项目中。
问题是,如果在上述任何步骤中被打断,那么将不会添加任何任务,并且项目将保存在数据库中,但没有相关联的任务。这将在计算总任务持续时间和其他情况下导致错误。
我可以在同一页上实例化和保存这两条记录,这将解决问题。
但是,是否有一种方法可以在专用URL之间拆分Project
和Task
的创建,而不会导致没有任务的项目?
英文:
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:
- instantiate the newly-created project instance from the param in the URL
- create a number of tasks
- validate all the tasks
- 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] = <extract session params to PORO>
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论