【问题标题】:Conditional attributes in Active Model Serializers活动模型序列化程序中的条件属性
【发布时间】:2015-04-17 17:28:56
【问题描述】:

如何仅在某些条件为真时才呈现属性?

例如,我想在创建操作时呈现用户的令牌属性。

【问题讨论】:

  • 你可以覆盖attributes方法
  • @apneadiving 有没有更简单明了的方法?

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


【解决方案1】:

在最新版本(0.10.x)中,你也可以这样做:

class EntitySerializer < ActiveModel::Serializer
  attributes :id, :created_at, :updated_at
  attribute :conditional_attr, if: :condition?

  def condition?
    #condition code goes here
  end
end

例如:

class UserSerializer < ActiveModel::Serializer
  attributes :id, :username, :name, :email, :created_at, :updated_at
  attribute :auth_token, if: :auth_token?

  def created_at
    object.created_at.to_i
  end

  def updated_at
    object.updated_at.to_i
  end

  def auth_token?
    true if object.auth_token
  end
end

编辑(Joe Essey 建议):

此方法不适用于最新版本 (0.10)

0.8 版本更简单。您不必使用if: :condition?。相反,您可以使用以下约定来获得相同的结果。

class EntitySerializer < ActiveModel::Serializer
  attributes :id, :created_at, :updated_at
  attribute :conditional_attr

  def include_conditional_attr?
    #condition code goes here
  end
end

上面的例子看起来像这样。

class UserSerializer < ActiveModel::Serializer
  attributes :id, :username, :name, :email, :created_at, :updated_at
  attribute :auth_token

  def created_at
    object.created_at.to_i
  end

  def updated_at
    object.updated_at.to_i
  end

  def include_auth_token?
    true if object.auth_token
  end
end

更多详情请见0.8 documentation

【讨论】:

  • 库已更新。您不再需要attribute :foo, if: :bar。只需为您希望有条件地显示的每个属性命名一个函数,例如:include_foo? 并在那里进行布尔检查。它在答案中链接的文档中。
  • 谢谢@JoeEssey。我添加了你的建议。
  • include_foo?从 0.10 开始,该方法似乎不再有效
  • @RonLugge 我认为它仍然有效。请参阅正确的文档here
  • 抱歉,需要明确的是,自动include_foo? 方法似乎已被删除——您仍然可以向属性方法添加if: foo? 参数。
【解决方案2】:

你可以重写attributes方法,这里是一个简单的例子:

class Foo < ActiveModel::Serializer

  attributes :id

  def attributes(*args)
    hash = super
    hash[:last_name] = 'Bob' unless object.persisted?
    hash
  end

end

【讨论】:

  • 这对于添加动态属性来说非常棒。
  • 我绝对喜欢这种方法。它使添加一堆条件更加简洁,因为您不必为每个属性都有一个方法(无论如何这都是非常多余的)。
【解决方案3】:

您可以首先在序列化程序的“初始化”方法上设置一个条件。此条件可以从代码中的任何其他位置传递,包括在“initialize”作为第二个参数接受的选项哈希中:

class SomeCustomSerializer < ActiveModel::Serializer

  attributes :id, :attr1, :conditional_attr2, :conditional_attr2

  def initialize(object, options={})
    @condition = options[:condition].present? && options[:condition]
    super(object, options)
  end

  def attributes(*args)
    return super unless @condition  #get all the attributes
    attributes_to_remove = [:conditional_attr2, :conditional_attr2]
    filtered = super.except(*attributes_to_remove)
    filtered
  end
end

在这种情况下,attr1 将始终被传递,而如果条件为真,则条件属性将被隐藏。

您将在代码中的任何其他位置获得此自定义序列化的结果,如下所示:

custom_serialized_object = SomeCustomSerializer.new(object_to_serialize, {:condition => true})

我希望这很有用!

【讨论】:

    【解决方案4】:

    序列化器options 已合并到 ActiveModel 序列化器中,现在可用(从 0.10 开始)。

    【讨论】:

    • 不幸的是,您链接到的讨论没有提供任何有用的说明,说明在哪里可以找到这些选项或如何使用它们。
    【解决方案5】:

    覆盖是个好主意,但如果您使用super,将在删除您想要的内容之前计算属性。如果它对你没有影响,好的,但是当它有影响时,你可以使用它:

    def attributes(options={})
      attributes =
        if options[:fields]
          self.class._attributes & options[:fields]
        else
          self.class._attributes.dup
        end
    
      attributes.delete_if {|attr| attr == :attribute_name } if condition
    
      attributes.each_with_object({}) do |name, hash|
        unless self.class._fragmented
          hash[name] = send(name)
        else
          hash[name] = self.class._fragmented.public_send(name)
        end
      end
    end
    

    ps:v0.10.0.rc3

    【讨论】:

      【解决方案6】:

      以下是如何将参数直接传递给序列化程序实例,并根据序列化程序声明中的这些参数显示隐藏属性。

      它也适用于父子序列化器。

      控制器或父序列化器:

      ActiveModelSerializers::SerializableResource.new(object.locations, {
        each_serializer: PublicLocationSerializer,
        params: { 
          show_title: true
        },
      })
      

      带条件的序列化器:

      class PublicLocationSerializer < ActiveModel::Serializer
        attributes :id, :latitude, :longitude, :title
      
        def title
          object.title if @instance_options[:params][:show_title]
        end
      
      end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-03
        • 2023-04-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多