【问题标题】:Rails API Best Practice, JSON responsesRails API 最佳实践,JSON 响应
【发布时间】:2015-02-07 16:02:04
【问题描述】:

我正在开发带有单独 Rails/Angular 前端代码库的 Rails API 后端。 Rails API 的响应必须以某种方式构建以匹配前端的 flash 消息。 A(n)(稍微归结)示例控制器响应是

render json: {status: "Unauthorized", code: "AUTH.UNAUTHORIZED", fallback_msg: "Unauthorized request"}

所以基本上我所有的控制器都充满了这个,有时当一个方法有 5 个可能的响应时(例如:如果用户重置他们的电子邮件,响应可能是无效的密码、无效的电子邮件、电子邮件已经注册等)。一位同事建议将这些方法抽象到模型中,因此模型是对发送回这些消息的响应,然后控制器可以拥有

def ctrl_method user = User.update(password: password) render json: user, status(user) end (其中 status 是另一种基于对象的 status 属性提供 HTTP 状态代码的方法) 我的问题是这是最佳实践吗?我了解 Rails MVC,感觉发送 json 消息的责任属于控制器而不是模型。

【问题讨论】:

    标签: ruby-on-rails json model-view-controller


    【解决方案1】:

    在不知道更多细节的情况下,我会考虑利用关注点来处理状态。这允许在不混淆模型的情况下封装业务逻辑。所以你可以有

    module Concerns
      module Statuses
        def deal_with_show
          # business logic goes here to generate the status
        end
        def deal_with_index
          # business logic goes here to generate the status
        end
        def deal_with_create
          # business logic goes here to generate the status
        end
        def default_status
          # set a default status here
        end
      end
    end
    

    然后在控制器中

    class MyController < ApplicationController
      include Concerns::Statuses
    
      def index
        render json: deal_with_index
      end
    end
    

    当然,关注中的状态细分是任意的。然而,它可以被处理是有道理的:通过方法、动词或其他一些区别。

    这是concerns 的好消息。

    【讨论】:

    • 每个控制器方法都有自己的响应,不仅仅是get vs post,还有index vs show vs create等。
    • 好的,但这不会改变想法。使用关注点来组织跨控制器复制的逻辑是符合目的的。我将答案修改为更合适。
    【解决方案2】:

    如果您想处理 ActiveRecord 错误,我认为您使用 errors.full_messages 并对此类错误使用相同的代码和状态(状态:'Forbidden',代码:'')。

    请注意,您应该在语言环境文件see guide 中自定义您的消息。但是,如果您想将您的应用翻译成不同的语言,它会很有用。

    可以从控制器和操作中推断出成功消息(见下文)。

    class ApplicationController < ActionController::Base
     ...
    
     def render_errors(object)
       render json: {status: 'Forbidden', code: 'WRONG_DATA', fallback_msg: object.errors.full_messages.join(", ")} 
     end
    
     def render_success(message = nil)
       message ||= I18n.t("#{self.controller_name}.message.#{self.action_name}"
       render json: {status: 'OK', code: 'OK', fallback_msg: message}
     end
    end
    
    class SomeController < ApplicationController
      def update
        if @some.update(params)
          render_success
        else
          render_errors(@some)
        end
      end
    end
    

    【讨论】:

      【解决方案3】:

      我说你们都是对的。控制器应该负责发送消息,并且方法应该被抽象出来——只是不要到模型中,更像是一个存在于/lib 中的类。

      这也应该使测试更容易。

      【讨论】:

        猜你喜欢
        • 2015-08-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-19
        • 1970-01-01
        相关资源
        最近更新 更多