> ## Documentation Index
> Fetch the complete documentation index at: https://forest-chore-open-api.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Writing behavior

Forest allows replacing the default field writing behavior with your own custom logic.

This is useful when you want to change how a given field behaves, but also to make [computed fields](/product/process/fields/computed) writable.

## How does it work

The `replaceFieldWriting` function allows changing the behavior of any change by creating a new patch that will be applied to the record.

You should refrain from using handlers that have side effects (to perform error handling, validation, ...) and [use hooks instead](/product/process/advanced-concepts/hooks/overview).

## Making a field read-only

<Info>
  Achieve this without any code in the field settings in the Forest UI.
</Info>

## Examples

### Changing other fields in the same record

In the following example, editing or creating a `fullName` will update both `firstName` and `lastName` fields of the record.

<CodeGroup>
  ```javascript Node.js / Cloud theme={null}
  collection.replaceFieldWriting('fullName', value => {
    const [firstName, lastName] = value.split(' ');

    return { firstName, lastName };
  });
  ```

  ```ruby Ruby theme={null}
  collection.replace_field_writing('fullName') do |value|
    first_name, last_name = value.split(' ')
    { 'firstName' => first_name, 'lastName' => last_name }
  end
  ```
</CodeGroup>

### Having specific behavior only for updates

Define different behavior for `creations` and `updates`.

In this example, each time the `firstName` field is edited, we also want to update a timestamp field.

<CodeGroup>
  ```javascript Node.js / Cloud theme={null}
  collection.replaceFieldWriting('firstName', async (value, context) => {
    switch (context.action) {
      case 'create':
        return { firstName, firstNameLastEdited: null };

      case 'update':
        return { firstName, firstNameLastEdited: new Date().toISOString() };

      default:
        throw new Error('Unexpected value');
    }
  });
  ```

  ```ruby Ruby theme={null}
  collection.replace_field_writing('firstName') do |value, context|
    case context.action
    when 'create'
      { 'firstName' => value, 'firstNameLastEdited' => nil }
    when 'update'
      { 'firstName' => value, 'firstNameLastEdited' => Time.now.iso8601 }
    else
      raise 'Unexpected value'
    end
  end
  ```
</CodeGroup>

### Changing fields in related records

<Info>
  Handling relationships inside a `replaceFieldWriting` will only work for `ManyToOne` and `OneToOne` relationships.
</Info>

In this simple example, we have two collections that are linked together:

* The `Users` collection has a `job` and a `portfolioId` as foreignKey
* The `Portfolios` collection has a `title`

When the user updates his `job` field we want also to update the `title` of the portfolio by the `job` name.

<CodeGroup>
  ```javascript Node.js / Cloud theme={null}
  collection.replaceFieldWriting('job', (job, { action }) => {
    return { job, portfolio: { title: job } };
  });
  ```

  ```ruby Ruby theme={null}
  collection.replace_field_writing('job') do |job, context|
    { 'job' => job, 'portfolio' => { 'title' => job } }
  end
  ```
</CodeGroup>

<Info>
  If the relationships do not exist, they will be created with the given field values.
</Info>

Provide another `portfolioId` to update the relationships and their fields:

<CodeGroup>
  ```javascript Node.js / Cloud theme={null}
  collection.replaceFieldWriting('job', (job, { action }) => {
    return { job, portfolioId: 8, portfolio: { title: job } };
  });
  ```

  ```ruby Ruby theme={null}
  collection.replace_field_writing('job') do |job, context|
    { 'job' => job, 'portfolioId' => 8, 'portfolio' => { 'title' => job } }
  end
  ```
</CodeGroup>

Chain the relationships. For example, if a portfolio has a `one-to-one` relationship with the `formats` collection, you can update it by writing the right path.

<CodeGroup>
  ```javascript Node.js / Cloud theme={null}
  collection.replaceFieldWriting('job', (job, { action }) => {
    return { job, portfolioId: 8, portfolio: { title: job, format: { name: 'pdf' } } };
  });
  ```

  ```ruby Ruby theme={null}
  collection.replace_field_writing('job') do |job, context|
    { 'job' => job, 'portfolioId' => 8, 'portfolio' => { 'title' => job, 'format' => { 'name' => 'pdf' } } }
  end
  ```
</CodeGroup>
