【问题标题】:Sideloading conditionally with ActiveModel::Serializers使用 ActiveModel::Serializers 有条件地侧载
【发布时间】:2013-07-19 20:36:59
【问题描述】:

我正在使用 ActiveModel::Serializers 构建 API。使用参数有条件地侧载数据的最佳方法是什么?

所以我可以提出像GET /api/customers这样的请求:

"customers": {
   "first_name": "Bill",
   "last_name": "Gates"
}

还有GET /api/customers?embed=address,note

"customers": {
   "first_name": "Bill",
   "last_name": "Gates"
},
"address: {
   "street": "abc"
},
"note": {
   "body": "Banned"
}

类似的东西取决于参数。我知道 ActiveModel::Serializers 有 include_[ASSOCIATION]? 语法,但我怎样才能从我的控制器中有效地使用它?


这是我目前的解决方案,但并不整洁:

customer_serializer.rb:

def include_address?
  !options[:embed].nil? && options[:embed].include?(:address)
end

application_controller.rb:

def embed_resources(resources = [])
  params[:embed].split(',').map { |x| resources << x.to_sym } if params[:embed]
  resources
end

customers_controller.rb:

def show
  respond_with @customer, embed: embed_resources
end

一定是更简单的方法吗?

【问题讨论】:

    标签: ruby-on-rails json api active-model-serializers


    【解决方案1】:

    我也在寻找一种有效且干净的方法来做到这一点。

    我找到了一个解决方案,但它并不漂亮。

    在我的 BaseController/ApplicationController 我添加了这个方法:

    serialization_scope :params
    

    所以范围现在是 params Hash,我可以在我的序列化程序的 include_[ASSOCIATION]? 方法中使用它。

    def include_associations?
        if scope[:embed]
            embed = scope[:embed].split(',') 
            return true if embed.include?('associations')
        end
    end
    

    我不喜欢这种方法,因为如果我需要使用current_user 之类的范围来有条件地返回数据,例如管理员。

    但是这个解决方案在某些情况下可以工作。

    更新

    您可以传递view_context,而不是直接传递params

    您可以委托您的序列化程序以保留 params 名称而不是 scope

    在您的应用程序控制器中:

    serialization_scope :view_context
    

    在您的序列化程序中:

    delegate :params, to: :scope
    

    瞧,您可以在序列化程序的 include_[ASSOCIATION]? 方法中使用 params[:embed]。

    【讨论】:

    • 我喜欢您使用 view_context 提出的建议。是否可以使用 rspec 对此进行单元测试?
    • 我已经更新了我的问题,向您展示我是如何做到的。
    【解决方案2】:

    根据您的回答,我还有另一个解决方案,因为我想要类似的功能。根据文档,如果想要对关联序列化进行较低级别的控制,他们可以覆盖include_associations!

    例如:

    def include_associations!
        if scope[:embed]
            include! :addresses, {embed: :ids, include: true}
        else
            include! :addresses, {embed: :ids}
        end
    end
    

    【讨论】:

      【解决方案3】:

      了解 include_associations 非常有帮助!谢谢!请注意,使用 active_model_serializers gem(版本 0.8.3),您可以使用 @options 在控制器中设置上下文。例如,如果在你调用的控制器中

      render json: customer, include_addresses: true
      

      然后在 CustomerSerializer 中:

      has_many :addresses
      def include_associations!
        if @options[:include_addresses]
          include! :addresses
        end
      end
      

      然后地址将被序列化。如果您将include_addresses 设置为false 进行渲染,则它们不会。 对于较新版本的 active_model_serializers,请使用 serialization_options 而不是 @options

      【讨论】:

        猜你喜欢
        • 2014-06-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-01
        • 1970-01-01
        • 2013-12-04
        • 1970-01-01
        相关资源
        最近更新 更多