# Scope and context

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

Actions can have 3 different scopes: `Single`, `Bulk`, and `Global`.

The scope of an action defines how it can be triggered and which records it will target.

| -                                                          | Single                           | Bulk                                                   | Global                                                      |
| ---------------------------------------------------------- | -------------------------------- | ------------------------------------------------------ | ----------------------------------------------------------- |
| **Targeted records**                                       | One at a time                    | All selected and matching the current segment / search | Your choice among all matching the current segment / search |
| **Can be triggered from the List View**                    | When a single record is selected | When one or more records are selected                  | ✅                                                           |
| **Can be triggered from the Details View or Summary View** | ✅                                | ✅                                                      | 🚫                                                          |

## The `context` object

The `context` object is central to writing Actions controllers in Forest Admin.

There are two different object context. The first `ForestAdminDatasourceCustomizer::Decorators::Action::Context::ActionContext` is used for the actions of type Bulk or Global. And the second `ForestAdminDatasourceCustomizer::Decorators::Action::Context::ActionContextSingle` is only used with the actions of type Single

It is the bridge between all the data that your agent has access to and the action's execution. It is passed to the `execute` function as the first argument and provides access to the following properties:

* `get_record(field_names)` (or `get_records(field_names)` for `Bulk` and `Global` Actions)
* `get_record_id()` (or `get_record_ids()` for `Bulk` and `Global` Actions)
* `collection` the collection on which the action is declared, which can be queried using the [Forest Admin Query Interface](/developer-guide-agents-ruby/data-sources/getting-started/queries.md#collection-interface).
* `datasource` the composite data source who contains all your collections, which can be queried using the [Forest Admin Query Interface](/developer-guide-agents-ruby/data-sources/getting-started/queries.md#data-source-interface)
* `filter` a filter that can be used to query the collection, and which is based on action scope and the list of selected records.
* `caller` an object containing information about the user who is performing the action (see details below)
* `field_changed?(field_name)` the name of the field who has changed in the UI. [See an example of usage](/developer-guide-agents-ruby/agent-customization/actions/forms-dynamic.md#example-4-using-hasfieldchanged-to-reset-value)

### Ruby DSL: Simplified helper methods

When using the Ruby DSL syntax with `collection.action`, the `execute` block provides simplified helper methods that make your code more concise:

| Helper Method           | Traditional Equivalent                     | Description                                    |
| ----------------------- | ------------------------------------------ | ---------------------------------------------- |
| `record(fields)`        | `context.get_record(fields)`               | Get a single record (for Single actions)       |
| `records(fields)`       | `context.get_records(fields)`              | Get multiple records (for Bulk/Global actions) |
| `form_value(key)`       | `context.get_form_value(key)`              | Access form field values                       |
| `datasource`            | `context.datasource`                       | Access the datasource                          |
| `caller`                | `context.caller`                           | Access caller information                      |
| `success(message)`      | `result_builder.success(message: message)` | Return success result                          |
| `error(message)`        | `result_builder.error(message: message)`   | Return error result                            |
| `file(content:, name:)` | `result_builder.file(...)`                 | Return file download                           |

These helper methods are only available when using the DSL syntax with `execute do ... end` blocks. For traditional syntax using `BaseAction.new`, continue using the full `context.get_record` style methods.

**Example:**

#### Traditional Syntax

Using full context methods with `customize_collection`:

```ruby
@create_agent.customize_collection('orders') do |collection|
  collection.add_action(
    'Mark as shipped',
    BaseAction.new(scope: ActionScope::SINGLE, form: [...])
  ) do |context, result_builder|
    order = context.get_record(['reference'])
    tracking = context.get_form_value('tracking_number')

    result_builder.success(message: "Order #{order['reference']} shipped!")
  end
end
```

#### DSL Syntax

Using simplified helper methods with `collection.action`:

```ruby
@create_agent.collection :orders do |collection|
  collection.action 'Mark as shipped', scope: :single do
    form do
      field :tracking_number, type: :string
    end

    execute do
      order = record(['reference'])           # Simplified
      tracking = form_value(:tracking_number) # Simplified

      success "Order #{order['reference']} shipped! Tracking: #{tracking}"
    end
  end
end
```

### The `caller` object

The `caller` object contains information about the current user performing the action:

| Property    | Description                   |
| ----------- | ----------------------------- |
| `id`        | User ID                       |
| `email`     | User email                    |
| `firstName` | First name                    |
| `lastName`  | Last name                     |
| `team`      | Team name                     |
| `role`      | Role name                     |
| `tags`      | Custom tags (key-value pairs) |
| `timezone`  | User timezone                 |

### Error methods

The context also provides methods to throw errors that will be displayed in the Forest Admin UI:

| Method                            | Description                |
| --------------------------------- | -------------------------- |
| `throw_validation_error(message)` | Display a validation error |
| `throw_forbidden_error(message)`  | Display a forbidden error  |
| `throw_error(message)`            | Display a generic error    |

### Example 1: Getting data from the selected records

We can simply use the `get_record(field_names)` method to get any column from the selected record or a relation.

```ruby
# Traditional syntax
include ForestAdmin::Types

@create_agent.customize_collection('user') do |collection|
  collection.add_action(
    'Mark as live',
    BaseAction.new(scope: ActionScope::SINGLE) do |context|
      record = context.get_record(['name'])
        if record['name'] === 'John'
          # log with your favorite logger => 'hi John'
        else
          # log with your favorite logger => 'You are not John!'
        end
    end
  )
end

# DSL syntax (simplified)
@create_agent.collection :user do |collection|
  collection.action 'Call me John in the server logs', scope: :single do
    execute do
      # Use simplified helper methods in the DSL
      user = record(['name'])  # Instead of context.get_record(['name'])

      if user['name'] == 'John'
        # log with your favorite logger => 'hi John'
      else
        # log with your favorite logger => 'You are not John!'
      end
    end
  end
end
```

### Example 2: Updating a field of the selected record

For simple queries, use `context.collection` and `context.filter` to query the collection.

Those are instances of objects from the [Forest Admin Query Interface](/developer-guide-agents-ruby/data-sources/getting-started.md).

```ruby
include ForestAdmin::Types

@create_agent.customize_collection('user') do |collection|
  collection.add_action(
    'Mark as live',
    BaseAction.new(scope: ActionScope::SINGLE) do |context|
      context.collection.update(context.filter, { name: 'foo' })
    end
  )
end

```

### Example 3: Coding any business logic

Forest Admin does not impose any restriction on the handler: you are free to write the `execute` handler to fit your use case.

You are free to call external APIs, query your database, or perform any work in action handlers.

```ruby
include ForestAdmin::Types

@create_agent.customize_collection('user') do |collection|
  collection.add_action(
    'Mark as live',
    BaseAction.new(scope: ActionScope::SINGLE) do |_context|
      res = HTTParty.get('http://my-api.com/mark-as-live')
    end
  )
end
```


---

# 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/agent-customization/actions/scope-context.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.
