# Payload conversion - Ruby SDK

> Customize how Temporal serializes application objects using Payload Converters in the Ruby SDK.

## Payload conversion 

Temporal SDKs provide a default [Payload Converter](/payload-converter) that can be customized to convert a custom data type to [Payload](/dataconversion#payload) and back.

### Conversion sequence 

The order in which your encoding Payload Converters are applied depend on the order given to the Data Converter.
You can set multiple encoding Payload Converters to run your conversions.
When the Data Converter receives a value for conversion, it passes through each Payload Converter in sequence until the converter that handles the data type does the conversion.

Payload Converters can be customized independently of a Payload Codec.
Temporal's Converter architecture looks like this:

![Temporal converter architecture](/img/info/converter-architecture.png)

## Supported Data Types 

Data converters are used to convert raw Temporal payloads to/from actual Ruby types.
A custom data converter can be set via the `data_converter` keyword argument when creating a client. Data converters are a combination of payload converters, payload codecs, and failure converters.
Payload converters convert Ruby values to/from serialized bytes. Payload codecs convert bytes to bytes (e.g. for compression or encryption). Failure converters convert exceptions to/from serialized failures.

Data converters are in the `Temporalio::Converters` module.
The default data converter uses a default payload converter, which supports the following types:

- `nil`
- "bytes" (i.e. `String` with `Encoding::ASCII_8BIT` encoding)
- `Google::Protobuf::MessageExts` instances
- [JSON module](https://docs.ruby-lang.org/en/master/JSON.html) for everything else

This means that normal Ruby objects will use `JSON.generate` when serializing and `JSON.parse` when deserializing (with `create_additions: true` set by default).
So a Ruby object will often appear as a hash when deserialized.
Also, hashes that are passed in with symbol keys end up with string keys when deserialized.
While "JSON Additions" are supported, it is not cross-SDK-language compatible since this is a Ruby-specific construct.

The default payload converter is a collection of "encoding payload converters".
On serialize, each encoding converter will be tried in order until one accepts (default falls through to the JSON one).
The encoding converter sets an `encoding` metadata value which is used to know which converter to use on deserialize.
Custom encoding converters can be created, or even the entire payload converter can be replaced with a different implementation.

**NOTE:** For ActiveRecord, or other general/ORM models that are used for a different purpose, it is not recommended to try to reuse them as Temporal models.
Eventually model purposes diverge and models for a Temporal workflows/activities should be specific to their use for clarity and compatibility reasons.
Also many Ruby ORMs do many lazy things and therefore provide unclear serialization semantics.
Instead, consider having models specific for workflows/activities and translate to/from existing models as needed.
See the next section on how to do this with ActiveModel objects.

#### ActiveModel 

By default, ActiveModel objects do not natively support the `JSON` module.
A mixin can be created to add this support for ActiveModel, for example:

```ruby
module ActiveModelJSONSupport
  extend ActiveSupport::Concern
  include ActiveModel::Serializers::JSON

  included do
    def as_json(*)
      super.merge(::JSON.create_id => self.class.name)
    end

    def to_json(*args)
      as_json.to_json(*args)
    end

    def self.json_create(object)
      object = object.dup
      object.delete(::JSON.create_id)
      new(**object.symbolize_keys)
    end
  end
end
```

Now if `include ActiveModelJSONSupport` is present on any ActiveModel class, on serialization `to_json` will be used which will use `as_json` which calls the super `as_json` but also includes the fully qualified class name as the JSON
`create_id` key.
On deserialization, Ruby JSON then uses this key to know what class to call `json_create` on.
