【问题标题】:non-RESTful actions in RailsRails 中的非 RESTful 操作
【发布时间】:2016-05-05 05:25:26
【问题描述】:

好的,趁着 GitHub 宕机,一个代码设计问题:
我总是在 Rails 应用程序中使用非标准 RESTful 操作(通常情况下)导致分析瘫痪。

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

这是我看到的选项:

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

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

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

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

我将使用如下嵌套路由:

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

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

一)

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

我可以自己整理路线,而无需更改控制器,就像:

b)

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

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

c)

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

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

d)

POST /admin/jobs/:job_id/cancel
POST /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-on-rails rest


    【解决方案1】:

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

    答案

    只需将cancelreactivate 添加到现有的JobsController

    使用此代码:

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

    创建如下路线:

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

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

    (另一种建议的方法是修补现有的 update 方法,状态为已取消;尽管我想这需要在 cancels 与常规 updates 的更新方法中设置条件)

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

    • 当你被推销“REST 是最好的!”时,为非资源提供资源是一个常见的陷阱。 (即,Jobs 是资源,但 JobCancellations 不是真正的资源,所以不要试图将它们变成资源)。

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

    • IMO 完全采用 REST 仅在您不太可能遇到的某些情况下有用,除非您在一家大公司。

    • 制作有意义的 API。 Rails 只是提供了轻松执行 CRUD 的方法。这与宁静有关,但不是全部。

    • REST(或 HATEOS)方法是让 /jobs/1234.json 包含 cancelLink: {url: "url", method: "POST", rel: "link to the docs"} 属性

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

    • fwiw,我使用了一堆“rest”API,这些 API 根据 rest 设计得很好,但作为开发人员使用起来很糟糕。 A) 涵盖原语和 B) 使其易于使用比始终遵守 REST(或 HATEOS,或您今天关注的任何东西)更重要。

    以上所有内容基本上都指向我一直试图告诉自己的建议:“最重要的是代码简单易懂。设计模式只有在帮助您实现该目标时才有用。如果设计模式没有达到那个目标,很可能你使用不正确,或者将它应用于不正确的情况,或者过于死板地遵循它”。

    【讨论】:

    • 我非常感谢这篇文章,尤其是最后一段。不仅仅是一个答案,而是提供更多信息。开发人员多次批评我认为只有 REST 是可以接受的。
    【解决方案2】:

    在这种特殊情况下,为什么不直接拥有

    # Cancel a job (handled by your cancellations controller)
    DELETE /admin/jobs/:job_id
    
    # Likewise, reactivate a job if so instructed by the request body
    PATCH /admin/jobs/:job_id
    

    我认为我不太愿意参与一般性的“你没有正确地使用 REST”辩论,有很多可能性;这个特殊案例看起来有一个不错的解决方案。

    FWIW,您真的需要允许重新激活同一个作业吗?取消后要求创建新作业可能更清楚。也许提供一些机制来克隆现有的工作。

    【讨论】:

    • 谢谢。我在 Ruby Australia slack 频道上对此进行了很好的讨论。该建议与您的建议相差不远,但有一些值得了解的额外信息。我会尽快将其合并为答案。顺便说一句,是的,肯定需要重新激活。
    • 几件事。 (1) 取消是错误的词;称之为停用。 (2) JobCancellation 不是资源,而是任务/动作。 (3) 我认为资源是嵌套在 Job 下的“活动”标志 - 将其设置为 true 或 false。
    • 是的,这很有道理。那么你会有一个 JobActiveFlagsController 吗?
    • 我不知道你是否可以假设它像一个标志一样简单;取消作业可能会创建一些值得注意的资源,这些资源更接近于创建某些东西的语义,或者至少比标志更宏大,例如您可以记录取消它的用户,它被取消的时间,这样即使我使用delete 的建议也不能准确地代表资源。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-04
    • 2015-01-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多