Conditional attributes in Active Model Serializers

前端 未结 5 1036
盖世英雄少女心
盖世英雄少女心 2020-12-08 00:19

How do I render an attribute only if some condition is true?

For example, I want to render User\'s token attribute on create action.

相关标签:
5条回答
  • 2020-12-08 00:50

    You could start by setting a condition on the serializers 'initialize' method. This condition can be passed from wherever else in your code, included in the options hash that 'initialize' accepts as second argument:

    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
    

    In this case attr1 would always be passed, while the conditional attributes would be hidden if the condition is true.

    You would get the result of this custom serialization wherever else in your code as follows:

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

    I hope this was useful!

    0 讨论(0)
  • 2020-12-08 00:52

    you can override the attributes method, here is a simple example:

    class Foo < ActiveModel::Serializer
    
      attributes :id
    
      def attributes(*args)
        hash = super
        hash[:last_name] = 'Bob' unless object.persisted?
        hash
      end
    
    end
    
    0 讨论(0)
  • 2020-12-08 00:59

    You can also do it this way:

    class EntitySerializer < ActiveModel::Serializer
      attributes :id, :created_at, :updated_at
      attribute :conditional_attr, if: :condition?
    
      def condition?
        #condition code goes here
      end
    end
    

    For example:

    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
    

    EDIT (Suggested by Joe Essey) :

    This method doesn't work with latest version (0.10)

    With the version 0.8 it is even simpler. You don't have to use the if: :condition?. Instead you can use the following convention to achieve the same result.

    class EntitySerializer < ActiveModel::Serializer
      attributes :id, :created_at, :updated_at
      attribute :conditional_attr
    
      def include_conditional_attr?
        #condition code goes here
      end
    end
    

    The example above would look like this.

    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
    

    See 0.8 documentation for more details.

    0 讨论(0)
  • 2020-12-08 01:02

    Override is a good idea, but if you use the super the attributes will be calculated before you remove what you want. If it does not make difference to you, ok, but when it does, you can use it:

    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

    0 讨论(0)
  • 2020-12-08 01:05

    Serializer options were merged into ActiveModel Serializers and now are available (since 0.10).

    0 讨论(0)
提交回复
热议问题