# Structure declaration

{% hint style="success" %}
This is the official documentation of the `agent_ruby` Ruby agent.
{% endhint %}

Creating a custom data source always starts with declaring the structure of the data

* Which collections are present?
* What fields do they contain?
* What are their types?

## Columns

### Examples

```ruby
module App
  module Collections
    class Movie < ForestAdminDatasourceToolkit::Collection
      include ForestAdminDatasourceToolkit::Schema
      include ForestAdminDatasourceToolkit::Components::Query:: ConditionTree

      def initialize(datasource)
        super(datasource, 'Movie')

        add_field('id', ColumnSchema.new(
          column_type: 'Number',
          is_primary_key: true,
        ))

        add_field('title', ColumnSchema.new(
          column_type: 'String',
          filter_operators: [Operators::PRESENT],
        ))

        add_field('mpa_rating', ColumnSchema.new(
          column_type: 'Enum',
          default_value: 'G',
          enum_values: %w[G PG PG-13 R NC-17],
        ))

        add_field('stars', ColumnSchema.new(
          column_type: [
            {
              'firstName' => 'String',
              'lastName'  => 'String',
            },
          ]
        ))
    end
  end
end
```

### Typing

The typing system for columns is the same as the one used when declaring fields in the agent customization step.

You can read all about it in ["Under the hood > Data Model > Typing"](https://docs.forestadmin.com/developer-guide-agents-ruby/under-the-hood/data-model/typing).

### Validation

When using primitive type fields, Forest Admin supports declaring a validation clause, which will be imported into the UI of the admin panel to validate records before creating/updating them.

The API for validation is the same as with [condition trees](https://docs.forestadmin.com/developer-guide-agents-ruby/getting-started/queries/filters#condition-trees), besides the fact that there is no `"field"` entry.

```json
{
  "aggregator": "and",
  "conditions": [
    { "operator": "present" },
    { "operator": "like", "value": "found%" },
    { "operator": "today" }
  ]
}
```

## Relationships

{% hint style="warning" %}
Only **intra**-data source relationships should be declared at the collection level.

For **inter**-data source relationships, you should use [jointures at the customization step](https://docs.forestadmin.com/developer-guide-agents-ruby/agent-customization/relationships).
{% endhint %}

You can declare relationships at the collection level, but that means that the data source you are making is responsible for handling them.

This will work out of the box for data sources using the "local-cache" strategy, however, please read ["Intra-data source Relationships"](https://docs.forestadmin.com/developer-guide-agents-ruby/data-sources/custom/translation/relationships), before starting with the "query translation" strategy.

### Examples

```ruby
module App
  module Collections
    class Movie < ForestAdminDatasourceToolkit::Collection
      include ForestAdminDatasourceToolkit::Schema
      # [...]

      add_field('director', ManyToOneSchema.new(
        foreign_key: 'director_id',
        foreign_key_target: 'id',
        foreign_collection: 'People'
      ))

      add_field('actors', ManyToManySchema.new(
        origin_key: 'movie_id',
        origin_key_target: 'id',
        foreign_key: 'actor_id',
        foreign_key_target: 'id',
        foreign_collection: 'People',
        through_collection: 'ActorsOnMovies'
      ))
    end
  end
end

```

### Typing

The typing system for relationships is the same as the one used when declaring jointures in the agent customization step.

You can read all about it in ["Under the hood > Data Model > Relationships"](https://docs.forestadmin.com/developer-guide-agents-ruby/under-the-hood/data-model/relationships).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.forestadmin.com/developer-guide-agents-ruby/data-sources/custom/translation/structure.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
