【问题标题】:How can I make an ActiveModel::Serializer attribute optional at runtime?如何在运行时使 ActiveModel::Serializer 属性可选?
【发布时间】:2015-09-09 18:55:50
【问题描述】:

我正在尝试允许 API 请求指定要在对象上返回的字段。我可以只用指定的字段来检索对象,但是当它被序列化时,它会抛出一个错误:

ActiveModel::MissingAttributeError (missing attribute: x)

如何使用ActiveModel::Serializer 实现此功能,是否可行?

【问题讨论】:

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


    【解决方案1】:

    我在寻找从 json 响应中删除可选字段的好方法时发现了这个问题。

    gem active_model_serializers 确实有一个解决方案。您只需在序列化程序声明中将条件传递给attribute 方法。

    class MySelectiveSerializer < ActiveModel::Serializer
      attributes :id, :anything
      attribute :something, if: -> { object.something.present? }
    end
    

    也许 3 年前没有这样的解决方案,但现在可以使用。 :)

    干杯。

    【讨论】:

    • 这是在哪个版本推出的?您可以链接到参考资料吗?
    【解决方案2】:

    这是因为Serializer.attributes 方法使用ActiveModel.read_attribute 方法调用每个字段。此方法将应用一些验证,例如模型定义中的validates_presence_of,这将引发异常。为了避免这种情况,我给出了三个不好的解决方案之后有一个更好更简单的解决方案:

    • 更改模型定义,但您将错过验证。
    • 覆盖方法ActiveModel.read_attribute来处理这种行为,你会遇到新的挑战。
    • 覆盖Serializer.attributes,而不是调用super,而是调用object.attributes

    但最好的选择是创建一个新的序列化类,以避免除了效果之外,只包含您想要的字段。然后在控制器类中指定:

    render json: People.all.reduced, each_serializer: SimplePersonSerializer
    

    编辑 1

    正确答案应该是来自Maurício Linhares的答案。

    render json: result.to_json( only: array_of_fields )
    

    【讨论】:

    • 最终的建议不符合挑战。 OP 希望 API 使用者能够指定任何字段组合,而不是特定的预定义子集。
    • @Adamantish 谢谢你,我没有意识到它应该是灵活的,我的错 =(
    【解决方案3】:

    您可以从序列化程序中删除属性,但它们应该存在。

    class SomeSerializer < ActiveModel::Serializer
      attributes :something
    
      def attributes
         super.except(:something) if something
       end
    end
    

    【讨论】:

      【解决方案4】:

      您可以通过在序列化程序中实现filter 方法来自定义属性。请注意,我描述的是最新的稳定版(在撰写本文时)0.9.x 分支。

      class PostSerializer < ActiveModel::Serializer
        attributes :id, :title, :body, :author
      
        def filter(keys)
          if scope.admin?
            keys
          else
            keys - [:author]
          end
        end
      end
      

      【讨论】:

      • 没有解决问题过滤器在查找所有属性后被调用,所以仍然抛出错误。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-07
      相关资源
      最近更新 更多