# app/avo/resources/project.rb
class Avo::Resources::Project < Avo::BaseResource
  def fields
    # fields here
  end

  def actions
    action Avo::Actions::DownloadFile
  end
end
```
:::
</Option>

<Option name="`keep_modal_open`" headingSize=3>

There might be situations where you want to run an action and if it fails, respond back to the user with some feedback but still keep it open with the inputs filled in.

`keep_modal_open` will tell Avo to keep the modal open.

```ruby
class Avo::Actions::KeepModalOpenAction < Avo::BaseAction
  self.name = "Keep Modal Open"
  self.standalone = true

  def fields
    field :name, as: :text
    field :birthday, as: :date
  end

  def handle(fields:, **args)
    User.create fields
    succeed "All good ✌️"
  rescue => error
    error "Something happened: #{error.message}"
    keep_modal_open
  end
end
```
</Option>

<Option name="`close_modal`" headingSize=3>

<VersionReq version="3.3.0" class="mt-4" />

This type of response becomes useful when you are working with a form and need to execute an action without redirecting, ensuring that the form remains filled as it is.

`close_modal` will flash all the messages gathered by [action responses](#action-responses) and will close the modal using turbo streams keeping the page still.

```ruby{7,9}
class Avo::Actions::CloseModal < Avo::BaseAction
  self.name = "Close modal"

  def handle(**args)
    # do_something_here
    succeed "Modal closed!!"
    close_modal
    # or
    do_nothing
  end
end
```
</Option>

<Option name="`do_nothing`" headingSize=3>

`do_nothing` is an alias for `close_modal`.

```ruby{7}
class Avo::Actions::CloseModal < Avo::BaseAction
  self.name = "Close modal"

  def handle(**args)
    # do_something_here
    succeed "Modal closed!!"
    do_nothing
  end
end
```
</Option>

<Option name="`navigate_to_action`" headingSize=3>

<VersionReq version="3.4.2" class="mt-4" />

You may want to redirect to another action. Here's an example of how to create a multi-step process, passing arguments from one action to another.
In this example the initial action prompts the user to select the fields they wish to update, and in the subsequent action, the chosen fields will be accessible for updating.

:::code-group
```ruby[PreUpdate]
class Avo::Actions::City::PreUpdate < Avo::BaseAction
  self.name = "Update"

  def fields
    field :name, as: :boolean
    field :population, as: :boolean
  end

  def handle(query:, fields:, **args)
    navigate_to_action Avo::Actions::City::Update,
      arguments: {
        cities: query.map(&:id),
        render_name: fields[:name],
        render_population: fields[:population]
      }
  end
end
```

```ruby[Update]
class Avo::Actions::City::Update < Avo::BaseAction
  self.name = "Update"
  self.visible = -> { false }

  def fields
    field :name, as: :text if arguments[:render_name]
    field :population, as: :number if arguments[:render_population]
  end

  def handle(fields:, **args)
    City.find(arguments[:cities]).each do |city|
      city.update! fields
    end

    succeed "City updated!"
  end
end
```
:::

You can see this multi-step process in action by visiting the [avodemo](https://main.avodemo.com/avo/resources/cities). Select one of the records, click on the "Update" action, choose the fields to update, and then proceed to update the selected fields in the subsequent action.
</Option>

<Option name="`append_to_response`" headingSize=3>

<VersionReq version="3.10.3" class="mt-4" />

Avo action responses are in the `turbo_stream` format. You can use the `append_to_response` method to append additional turbo stream responses to the default response.

```ruby{5-7}
def handle(**args)
  succeed "Modal closed!!"
  close_modal

  append_to_response -> {
    turbo_stream.set_title("Cool title ;)")
  }
end
```

The `append_to_response` method accepts a Proc or lambda function. This function is executed within the context of the action's controller response.

The block should return either a single `turbo_stream` response or an array of multiple `turbo_stream` responses.

:::code-group
```ruby[Array]{2-5}
append_to_response -> {
  [
    turbo_stream.set_title("Cool title"),
    turbo_stream.set_title("Cool title 2")
  ]
}
```

```ruby[Single]{2}
append_to_response -> {
  turbo_stream.set_title("Cool title")
}
```
:::
</Option>

<Option name="`reload_records`" headingSize=3>

<VersionReq version="3.14.0" class="my-4" />

<div style="position: relative; padding-bottom: 56.25%; height: 0;"><iframe src="https://www.loom.com/embed/6b9ae6a3968c447f98ac4f9a161fe781?sid=17f08010-6a56-4e8c-8b80-692424327b55" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></iframe></div>

:::warning
This option **only** works on **Index** pages, **NOT** on **associations**.
:::

This option leverages Turbo Stream to refresh specific table rows (and grid view cards since <Version version="3.24.0"/>) in response to an action.

For individual records, you can use the `reload_record` alias method.

```ruby{8}
def handle(query:, fields:, **args)
  query.each do |record|
    record.update! active: !record.active

    record.notify fields[:message] if fields[:notify_user]
  end

  reload_records(query)
end
```

The `reload_records` and `reload_record` methods are aliases, and they accept either an array of records or a single record.

:::code-group
```ruby[Array]{1}
reload_records([record_1, record_2])
```

```ruby[Single]{1}
reload_record(record)
```
:::
</Option>

---