Rails 中的非 RESTful 操作 [英] non-RESTful actions in Rails

查看:49
本文介绍了Rails 中的非 RESTful 操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,当 GitHub 关闭时,一个代码设计问题:
我总是在 Rails 应用程序(以及一般情况下)中使用非标准 RESTful 操作进行分析瘫痪.

我有乔布斯,我希望能够取消(并重新激活)它们.它不像设置一个复选框那么简单;还有一些其他的事情需要发生.所以我不能只使用现有的 JobsController#update 操作.

以下是我的选择:

1. 只需将 cancelreactivate 添加到现有作业控制器即可.路线将类似于:

POST/admin/jobs/cancel/:job_idPOST/admin/jobs/reactivate/:job_id

(不是 RESTful;假设这是一个坏主意)

2. 使用 createdestroy 操作创建一个 JobCancellationsController.重新激活作业是 destroy-ing 一个 JobCancellation 资源.

我将使用如下嵌套路由:

resources :jobs, 除了: :show do资源 :job_cancellation, 仅: [:create, :destroy]结尾

默认情况下会给我类似的东西

a)

POST/admin/jobs/:job_id/job_cancellation删除/admin/jobs/:job_id/job_cancellation

我可以在不改变控制器的情况下自己整理路由,就像:

b)

POST/admin/jobs/:job_id/cancellation删除/admin/jobs/:job_id/cancellation

虽然这看起来不是很直观 - 'cancelation' 会比 cancel 更好.所以我可以在保持控制器不变的情况下更改路线:

c)

POST/admin/jobs/:job_id/cancel删除/admin/jobs/:job_id/cancel

第一条路线现在有意义(虽然严格来说它不是RESTful?),但第二条路线不是......删除作业取消"?因此,您可以将其更改为:

d)

POST/admin/jobs/:job_id/cancelPOST/admin/jobs/:job_id/reactivate

现在路由是有道理的,但看起来很接近上面的选项 1),即使路由确实映射到 JobCancellationsController 中的 RESTful 操作而不是 JobsController 中的非 RESTful 操作.将 POST/admin/jobs/:job_id/reactivate 路由映射到 JobCancellationsController#destroy 操作似乎非常奇怪.

为了避免使用 JobCancellationsController#destroy 的最后一种方式,我可以改为:

3. 与选项 2 类似,但创建两个控制器:JobCancellationsController 仅带有 create 操作,以及 JobReactivationsController 仅带有 create 操作.

执行此操作的正确"方法是什么?或者至少,哪些是我可以快速消除的不正确"方式?有没有我错过的完全不同的更好的方法?

解决方案

在对 Ruby Australia slack 频道进行讨论后,我将建议合并到以下内容中:

答案

只需将 cancelreactivate 添加到现有的 JobsController 中即可.

使用此代码:

resources :jobs do发布:取消,在::成员发布:重新激活,在::成员结尾

创建路由,如:

POST/admin/jobs/:job_id/cancelPOST/admin/jobs/:job_id/reactivate

这既简单又直观,即使它不是严格的 RESTful.

(另一种建议的方法是 PATCH 到现有的 update 方法,状态为已取消;尽管我猜这需要在您的更新方法中为 cancels与常规更新)

讨论中提出的其他有用的观点

  • 为不是资源的东西提供资源是一个常见的陷阱,当您被出售时,REST 是最好的!"(即,Jobs 是一种资源,但 JobCancellations 并不是真正的资源,所以不要试图将它们变成一种资源.

  • 如果您不需要删除作业的能力,您可以使用 destroy 操作而不是 cancel 操作来取消作业.>

  • IMO 全面 REST 仅在某些情况下有用,除非您在大型公司,否则您不太可能遇到这些情况.

  • 制作一个有意义的 API.Rails 只是提供了轻松完成 CRUD 工作的方法.这与宁静有关,但还不是全部.

  • REST(或 HATEOS)方法是让 /jobs/1234.json 包含一个 cancelLink: {url: "url", method: "POST", rel: "链接到文档"} 属性

  • 当我们构建 API 时,我们有一个非官方规则,如果我们不确定要做什么,我们就复制 github 所做的,因为我们喜欢他们的 API.

  • fwiw,我使用了一堆根据 rest 精心设计的rest"API,但作为开发人员使用起来却很糟糕.与始终遵守 REST(或 HATEOS,或您今天关注的任何内容)相比,A) 涵盖原语和 B) 使其易于使用更重要.

以上所有内容基本上都指向了我总是试图告诉自己的建议:最重要的是代码简单易懂.设计模式仅在帮助您实现该目标的范围内有用.如果设计模式没有达到那个目标,很可能你使用它不正确,或者将它应用于不正确的情况,或者过于严格地遵循它".

OK, while GitHub is down, a code design question:
I always get analysis paralysis with non-standard RESTful actions in rails apps (and generally).

I've got Jobs, and I want to be able to cancel (and re-activate) them. It's not as simple as setting a checkbox; there's a few other things that need to happen., so I can't just use the existing JobsController#update action.

Here are my options as I see it:

1. Just add cancel and reactivate to existing jobs controller. The routes would be something like:

POST /admin/jobs/cancel/:job_id
POST /admin/jobs/reactivate/:job_id

(Not RESTful; assuming this is a bad idea)

2. Create a JobCancellationsController with create and destroy actions. Re-activating a job is destroy-ing a JobCancellation resource.

I'll use nested routes as per below:

resources :jobs, except: :show do
  resource :job_cancellation, only: [:create, :destroy]
end

which by default will give me something like

a)

POST /admin/jobs/:job_id/job_cancellation
DELETE /admin/jobs/:job_id/job_cancellation

I could tidy the routes themselves up, without changing the controller, to be like:

b)

POST /admin/jobs/:job_id/cancellation
DELETE /admin/jobs/:job_id/cancellation

Although that doesn't seem very intuitive - 'cancellation' would be better as cancel. So I can change the routes while keeping the controller the same:

c)

POST /admin/jobs/:job_id/cancel
DELETE /admin/jobs/:job_id/cancel

That first route now makes sense (although it's not RESTful strictly speaking?), but the second doesn't... "deleting a job cancel"? So you'd change it to something like:

d)

POST /admin/jobs/:job_id/cancel
POST /admin/jobs/:job_id/reactivate

Now the routes makes sense, but look suspiciously close to option 1) above, even though the routes do map to RESTful actions in the JobCancellationsController rather than non-RESTful actions in the JobsController. And it seems very bizzare to have the POST /admin/jobs/:job_id/reactivate route mapping to the JobCancellationsController#destroy action.

To avoid that last odity with JobCancellationsController#destroy, I could instead do:

3. Similar to option 2, but create two controllers: JobCancellationsController with a create action only, and JobReactivationsController with a create action only.

What's the 'correct' way to do this? Or at least, which are the 'incorrect' ways that I can quickly eliminate? Is there a totally different, better way that I've missed?

解决方案

After a discussion on the Ruby Australia slack channel, I've consolidated the advice into the below:

The Answer

Just add cancel and reactivate to the existing JobsController.

Use this code:

resources :jobs do
  post :cancel, on: :member
  post :reactivate, on: :member
end

to create routes like:

POST /admin/jobs/:job_id/cancel
POST /admin/jobs/:job_id/reactivate

This is simple and intuitive, even if it's not strictly RESTful.

(Another advised approach was to PATCH to the existing update method with a status of cancelled; though I guess that'd require a conditional in your update method for cancels vs regular updates)

Other useful points that came out in the discussion

  • resourcing things that aren't resources is a common trap when you're being sold "REST is the best!" (ie, Jobs are a resource, but JobCancellations aren't really, so don't try to make them a resource).

  • If you don't need the ability to delete a job, you could use the destroy action to cancel jobs instead of a cancel action.

  • IMO going full REST is only useful in certain contexts that you aren't likely to encounter unless you're at a big corp.

  • Make an API that makes sense. Rails just provides ways to do CRUD stuff easily. That ties in to restful but isn't all of it.

  • the REST (or HATEOS) way to do it is to have /jobs/1234.json include a cancelLink: {url: "url", method: "POST", rel: "link to the docs"} property

  • when we were building our API we had an unofficial rule that if we weren't sure what to do, we'd just copy what github do, as we like their API.

  • fwiw, I’ve used a bunch of "rest" APIs that were well designed according to rest, but horrible to use as a developer. It’s more important that you A) cover primitives and B) make it friendly to use than you abide by REST (or HATEOS, or whatever you're focusing on today) all the time.

All of the above basically points to advice I always try to tell myself: "It's most important that the code is simple and easy to understand. Design patters are useful only to the extent that they help you achieve that goal. If a design pattern doesn't achieve that goal, it's likely you're using it incorrectly, or applying it to an incorrect situation, or following it too rigidly".

这篇关于Rails 中的非 RESTful 操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆