### Install AshDispatch with mix igniter.install Source: https://hexdocs.pm/ash_dispatch Run this command to install AshDispatch with all required resources, domains, and configuration automatically. After running it, you must run the migration commands. ```elixir mix igniter.install ash_dispatch ``` -------------------------------- ### Add ash_dispatch dependency to mix.exs Source: https://hexdocs.pm/ash_dispatch Add the AshDispatch dependency to your mix.exs file for manual installation. See the Getting Started guide for complete manual setup instructions. ```elixir def deps do [ {:ash_dispatch, "~> 0.5.0"} ] end ``` -------------------------------- ### Generate and run AshDispatch migrations Source: https://hexdocs.pm/ash_dispatch Run these commands after the quick-start installation to generate and apply the database migrations for AshDispatch. ```elixir mix ash.codegen add_ash_dispatch mix ash.migrate ``` -------------------------------- ### Define AshDispatch events in a resource DSL Source: https://hexdocs.pm/ash_dispatch Configure AshDispatch on a resource with the `extensions: [AshDispatch.Resource]` option and define events in the `dispatch` block. Events trigger on actions like `:create` or `:assign`; inline-complete events need no module, while email channels require templates generated by `mix ash.codegen`. Custom modules can be supplied via `module:` for complex events. After setup, events dispatch automatically when actions run, as shown by the `Ash.create!()` call that triggers the `:created` event. ```elixir # 1. Add extension to resource defmodule MyApp.Tickets.Ticket do use Ash.Resource, extensions: [AshDispatch.Resource] # 2. Define events dispatch do # Inline-complete event (no module needed!) # Works out of the box with just DSL configuration event :created, trigger_on: :create, channels: [ [transport: :in_app, audience: :user] ], content: [ notification_title: "Ticket Created", notification_message: "{{user_name}} created ticket #{{id}}" ], metadata: [ notification_type: :success ] # Event with email requires templates # Run `mix ash.codegen` to generate template stubs event :assigned, trigger_on: :assign, channels: [ [transport: :in_app, audience: :user], [transport: :email, audience: :user] ], content: [ subject: "Ticket #{{id}} assigned to you", notification_title: "Ticket Assigned" ] # Complex event with custom module (your override) event :escalated, trigger_on: :escalate, module: MyApp.Events.Tickets.Escalated end end # 3. That's it! Events dispatch automatically when actions run Ticket |> Ash.Changeset.for_create(:create, %{title: "Bug report"}) |> Ash.create!() # -> Automatically dispatches :created event # -> Creates in-app notification for user (no templates needed!)Copy ``` -------------------------------- ### Generate filenames and labels with AshDispatch.Naming Source: https://hexdocs.pm/ash_dispatch Generates consistent filenames and display labels for multi-audience templates. The filename/4 function produces a dot-separated string, and label/3 produces a human-readable label with audience and template type in parentheses. ```elixir # Generate audience-specific filenames AshDispatch.Naming.filename("email", :admin, "summary", "html") # => "email.admin.summary.html" # Generate display labels AshDispatch.Naming.label(:email, :admin, "summary") # => "email (admin, summary)" ``` -------------------------------- ### Configure real-time counter broadcasting with AshDispatch Source: https://hexdocs.pm/ash_dispatch Set up automatic real-time counter broadcasting with AshDispatch. Define counters in a resource, configure the broadcast function in config, and use the ChannelState helper in a Phoenix channel to load initial state. After creating an order, the counter update is automatically broadcast to the channel and the frontend receives a "counter_updated" event. ```elixir # 1. Define counters in your resource defmodule MyApp.Orders.ProductOrder do use Ash.Resource, extensions: [AshDispatch.Resource] counters do # User sees their own pending orders counter :pending_orders, trigger_on: [:create, :complete, :cancel], counter_name: :pending_orders, query_filter: [status: :pending], audience: :user, invalidates: ["orders"] # Admins see ALL pending orders counter :admin_pending_orders, trigger_on: [:create, :complete, :cancel], counter_name: :admin_pending_orders, query_filter: [status: :pending], audience: :admin, invalidates: ["orders", "analytics"] end end # 2. Configure broadcasting (one line!) # config/config.exs config :ash_dispatch, counter_broadcast_fn: {MyAppWeb.UserChannel, :broadcast_counter} # 3. Use helper in Phoenix Channel (one line!) defmodule MyAppWeb.UserChannel do alias AshDispatch.Helpers.ChannelState def handle_info(:after_join, socket) do # Loads ALL counters automatically - no manual queries! initial_state = ChannelState.build(socket.assigns.user_id) # => %{"counters" => %{"pending_orders" => 5}, "notifications" => [...]} push(socket, "initial_state", initial_state) {:noreply, socket} end end # 4. That's it! Counters update in real-time automatically Order.create!(%{status: :pending}) # -> Automatically broadcasts counter update to Phoenix Channel # -> Frontend receives "counter_updated" event with new valueCopy ``` -------------------------------- ### Enable compile_templates in config/prod.exs Source: https://hexdocs.pm/ash_dispatch Required for production releases. Enables template compilation so email templates are copied to priv/ash_dispatch/templates/ during compilation, ensuring they are available at runtime. Without this, templates won't load in production because lib/ source files aren't included in releases. ```elixir # config/prod.exs - REQUIRED for releases config :ash_dispatch, compile_templates: true ``` -------------------------------- ### Find event module and execute callback with AshDispatch.EventResolver Source: https://hexdocs.pm/ash_dispatch Finds an event module by ID and safely executes a callback with a default value. The find_module call returns {:ok, module} for a valid ID, and subject/4 uses the provided default when the callback fails or is absent. ```elixir # Find an event module {:ok, module} = AshDispatch.EventResolver.find_module("orders.created") # Safe callback execution with defaults subject = AshDispatch.EventResolver.subject(module, context, channel, default: "No subject") ``` -------------------------------- ### Define AshDispatch event in Ash resource Source: https://hexdocs.pm/ash_dispatch Define an Ash resource with the AshDispatch extension and declare a `:created` event triggered by the `:create_from_cart` action. The event uses the `:standard` priority, sends to in-app and email channels (email delayed by 300 seconds), and includes template content with `{{order_number}}` interpolation and metadata. ```elixir defmodule MyApp.Orders.ProductOrder do use Ash.Resource, extensions: [AshDispatch.Resource] actions do create :create_from_cart do accept [:user_id] # Your action logic... end end dispatch do event :created, trigger_on: :create_from_cart, priority: :standard, channels: [ [transport: :in_app, audience: :user], [transport: :email, audience: :user, delay: 300] ], content: [ subject: "Order #{{order_number}} created", notification_title: "Your order was created", notification_message: "Order #{{order_number}} is being processed" ], metadata: [ notification_type: :success ] end end ``` -------------------------------- ### Configure Oban cron for AshDispatch.Workers.RetryFailedDeliveries Source: https://hexdocs.pm/ash_dispatch Required configuration for the retry cron. Failed deliveries are only retried by AshDispatch.Workers.RetryFailedDeliveries; Oban's own job retries no-op once a receipt is failed. Schedule this cron and give it its :default queue. ```elixir config :my_app, Oban, queues: [emails: 10, default: 5], plugins: [ {Oban.Plugins.Cron, crontab: [{"*/15 * * * *", AshDispatch.Workers.RetryFailedDeliveries}]} ] ``` -------------------------------- ### Resolve channels with AshDispatch.ChannelResolver.resolve Source: https://hexdocs.pm/ash_dispatch Resolves channels for an event using the centralized resolver. DSL channels take precedence over module callbacks, and the result is a list of %Channel{} structs. Used internally by Dispatcher, ManualTrigger, and preview generators. ```elixir # Used internally by Dispatcher, ManualTrigger, preview generators, etc. channels = AshDispatch.ChannelResolver.resolve(event_id, event_module, context, dsl_channels: event_config.channels ) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.