ワンクリックで
create-resource-action
// Use when creating Backpex resource actions for global operations like bulk exports, invitations, imports, or any action that applies to the resource as a whole rather than individual items.
// Use when creating Backpex resource actions for global operations like bulk exports, invitations, imports, or any action that applies to the resource as a whole rather than individual items.
Use when scaffolding a new Backpex LiveResource, setting up admin CRUD views, or configuring adapter_config, fields, filters, and routing for a resource.
Use when creating custom Backpex field types, implementing the Backpex.Field behaviour, or adding fields to a LiveResource's fields/0 callback.
Use when adding a filter to a Backpex LiveResource, creating a filter module, or the user asks about filtering data in Backpex index views.
Use when upgrading Backpex to a newer version, handling breaking changes, or migrating code after a version bump. Also use when the user asks about what changed between versions.
Use when creating custom Backpex item actions, adding action buttons to table rows or the show page, or modifying the default edit/delete/show actions.
| name | create-resource-action |
| description | Use when creating Backpex resource actions for global operations like bulk exports, invitations, imports, or any action that applies to the resource as a whole rather than individual items. |
You are an expert at creating resource actions for Backpex. Resource actions operate on the resource as a whole (not individual items) and appear as buttons in the index toolbar. They open a slide-over with a form.
| Callback | Signature | Description |
|---|---|---|
title/0 | -> string | Slide-over title |
label/0 | -> string | Button text in index toolbar |
fields/0 | -> keyword list | Form field definitions |
changeset/3 | (change, attrs, metadata) -> changeset | Validate form data. metadata has :assigns and :target keys |
handle/2 | (socket, data) -> {:ok, socket} | {:error, changeset} | Execute the action with validated data |
| Callback | Default | Description |
|---|---|---|
base_schema/1 | schemaless changeset | Override to use a real Ecto schema |
defmodule MyAppWeb.ResourceActions.InviteUser do
use Backpex.ResourceAction
import Ecto.Changeset
@impl Backpex.ResourceAction
def title, do: "Invite User"
@impl Backpex.ResourceAction
def label, do: "Invite"
@impl Backpex.ResourceAction
def fields do
[
email: %{
module: Backpex.Fields.Text,
label: "Email",
type: :string
},
role: %{
module: Backpex.Fields.Select,
label: "Role",
options: [Admin: "admin", User: "user"],
prompt: "Select role...",
type: :string
}
]
end
@impl Backpex.ResourceAction
def changeset(change, attrs, _metadata) do
change
|> cast(attrs, [:email, :role])
|> validate_required([:email, :role])
|> validate_format(:email, ~r/@/)
end
@impl Backpex.ResourceAction
def handle(socket, data) do
case MyApp.Accounts.send_invitation(data.email, data.role) do
:ok ->
{:ok, Phoenix.LiveView.put_flash(socket, :info, "Invitation sent to #{data.email}.")}
{:error, reason} ->
{:ok, Phoenix.LiveView.put_flash(socket, :error, "Failed: #{reason}")}
end
end
end
defmodule MyAppWeb.ResourceActions.ExportPosts do
use Backpex.ResourceAction
import Ecto.Changeset
@impl Backpex.ResourceAction
def title, do: "Export Posts"
@impl Backpex.ResourceAction
def label, do: "Export"
@impl Backpex.ResourceAction
def fields do
[
format: %{
module: Backpex.Fields.Select,
label: "Format",
options: [CSV: "csv", JSON: "json"],
prompt: "Select format...",
type: :string
}
]
end
@impl Backpex.ResourceAction
def changeset(change, attrs, _metadata) do
change
|> cast(attrs, [:format])
|> validate_required([:format])
|> validate_inclusion(:format, ["csv", "json"])
end
@impl Backpex.ResourceAction
def handle(socket, data) do
# Trigger export...
{:ok, Phoenix.LiveView.put_flash(socket, :info, "Export started in #{data.format} format.")}
end
end
@impl Backpex.LiveResource
def resource_actions do
[
invite: %{module: MyAppWeb.ResourceActions.InviteUser},
export: %{module: MyAppWeb.ResourceActions.ExportPosts}
]
end
The keyword key (e.g. :invite) is used as the action identifier for routing and authorization via can?/3.
| Aspect | Resource Action | Item Action |
|---|---|---|
| Scope | Whole resource | Selected items |
| UI | Slide-over form | Modal dialog |
| Callbacks | title/0, label/0, handle/2 | icon/2, label/2, handle/3 |
| Form | Always has fields | Optional |
| Location | Index toolbar only | Row, index toolbar, show page |
lib/my_app_web/resource_actions/<snake_case_name>.exMyAppWeb.ResourceActions.<ActionName>type: key in each field map (e.g. type: :string). This is required for the schemaless changeset to work.can?(assigns, :action_key, nil) in the LiveResource (item is always nil){:error, changeset} from handle/2 to keep the form open and show validation errors