Conditional Attributes

:if and :unless skip an attribute depending on the serialized object. :if_value and :unless_value skip it depending on its value.

class UserSerializer < Serega
  attribute :email, if: :active?                                    # user.active?
  attribute :phone, if: proc { |user, ctx| ctx[:admin] }
  attribute :role, unless: proc { |user, ctx:| ctx[:public] }
  attribute :nickname, if_value: proc { |nickname| !nickname.nil? }
  attribute :rating, unless_value: :zero?                           # rating.zero?
end

UserSerializer.to_h(user, context: {admin: true})
# => {email: "bruce@wayne.com", phone: "555-0100", role: "admin", rating: 5}

Conditions

A condition is one of:

attribute :email, if: proc { |user, ctx| user == ctx[:current_user] }
attribute :email, if: EmailPolicy.method(:visible?) # EmailPolicy.visible?(user)
attribute :email, if_value: proc { |email, ctx| ctx[:show_emails] }

Order of checks

:if and :unless are checked before the value is found, so a skipped attribute does not compute its value. :if_value and :unless_value are checked after.

:unless is checked only when :if passes, and :unless_value only when :if_value passes.

:if_value and :unless_value can not be used with :serializer or a block. Use :if and :unless for relations.

Skipped attributes in results

.to_h omits skipped attributes. .to_struct and .to_data return nil for them, so all objects serialized with the same fields have the same members.

UserSerializer.to_h(user, context: {public: true})
# => {email: "bruce@wayne.com", rating: 5}

UserSerializer.to_struct(user, context: {public: true})
# => #<struct email="bruce@wayne.com", phone=nil, role=nil, nickname=nil, rating=5>

Errors

An error raised by a condition names the condition and the line where the attribute is defined:

(when checking the :if condition of the 'email' attribute in UserSerializer, app/serializers/user_serializer.rb:4)

To hide an attribute unless a client requests it, use hide: true, see Selecting fields.