Search documentation of ash

# View Source Generic Actions

Generic actions are so named because there are no special rules about how they work. A generic action takes arguments and returns a value. The struct used for building input for a generic action is `Ash.ActionInput`.

    action :say_hello, :string do
      argument :name, :string, allow_nil?: false

      run fn input, _ ->
        {:ok, "Hello: #{input.arguments.name}"}
      end
    end

A generic action declares its arguments, return type, and implementation, as illustrated above.

> ### No return? No problem!

> Generic actions can omit a return type, in which case running them returns `:ok` if successful.

>     action :schedule_job do
>       argument :job_name, :string, allow_nil?: false
>       run fn input ->
>         # Schedule the job
>         :ok
>       end
>     end

## Why use generic actions?

The example above could be written as a normal function in elixir, i.e

    def say_hello(name), do: "Hello: #{name}"

The benefit of using generic actions instead of defining normal functions:

- They can be used with api extensions like `ash_json_api` and `ash_graphql`
- Their inputs are type checked and casted
- They support Ash authorization patterns (i.e policies)
- They can be included in the code interface of a resource
- They can be made transactional with a single option (`transaction? true`)

If you don't need any of the above, then there is no problem with writing regular Elixir functions!

## Return types and constraints

Generic actions do not cast their return types. It is expected that the action return a valid value for the type that they declare. However, declaring additional constraints can inform API usage, and make the action more clear. For example:

    action :priority, :integer do
      constraints [min: 1, max: 3]
      argument :status, :atom, constraints: [one_of: [:high, :medium, :low]]

      run fn input, _ ->
        case input.arguments.status do
          :high -> {:ok, 3}
          :medium -> {:ok, 2}
          :low -> {:ok, 1}
        end
      end
    end

> #### Returning resource instances

> It sometimes happens that you want to make a generic action which returns an instance or instances of the resource. It's natural to assume that you can set your action's return type to the name of your resource. This won't work as resources do not define a type, unless they are embedded. In embedded resources, this won't work because the module is still being compiled, so referencing yourself as a type causes a compile error. Instead, use the `:struct` type and the `instance_of` constraint, like so:

>     action :get, :struct do
>       constraints instance_of: __MODULE__

>       run # ...
>     end

## Calling Generic Actions

To execute a generic action in Ash, follow these steps:

1. Prepare the action input: Use `Ash.ActionInput.for_action/4` to specify the resource, the action and its arguments.
2. Run the action: Use `Ash.run_action/2` to execute the action with the prepared input.

### Example Usage

Consider an `Ash.Resource` with the action `:say_hello`:

    action :say_hello, :string do
      argument :name, :string, allow_nil?: false

      run fn input, _ ->
        {:ok, "Hello: #{input.arguments.name}"}
      end
    end

Call this action:

    {:ok, greeting} = Resource
    |> Ash.ActionInput.for_action(:say_hello, %{name: "Alice"})
    |> Ash.run_action()

    IO.puts(greeting)  # Output: Hello: Alice

### Using Code Interface

You can also use Code Interfaces to call actions:

Given a definition like:

    define :say_hello, args: [:name]

    {:ok, greeting} = Resource.say_hello("Alice")
    greeting = Resource.say_hello!("Alice")

← Previous Page Destroy Actions
Next Page → Manual Actions