### Example of a preparation Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Resource.md A concrete example of using the prepare directive with sorting options. ```elixir prepare build(sort: [:foo, :bar]) ``` -------------------------------- ### Example authorize_if usage Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Policy.Authorizer.md Examples showing how to use authorize_if with different checks. ```elixir authorize_if logged_in() ``` ```elixir authorize_if actor_attribute_matches_record(:group, :group) ``` -------------------------------- ### Example of Waiting for a Specific Step Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Reactor.md An example demonstrating how to use `wait_for` to specify a step named `:create_user` that must complete first. ```elixir wait_for :create_user ``` -------------------------------- ### Example forbid_unless usage Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Policy.Authorizer.md Examples demonstrating how to use forbid_unless with different checks. ```elixir forbid_unless logged_in() ``` ```elixir forbid_unless actor_attribute_matches_record(:group, :group) ``` -------------------------------- ### Example authorize_unless usage Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Policy.Authorizer.md Examples illustrating how to use authorize_unless with different checks. ```elixir authorize_unless not_logged_in() ``` ```elixir authorize_unless actor_attribute_matches_record(:group, :blacklisted_groups) ``` -------------------------------- ### Example of a Destroy Step with Nested Configurations Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Reactor.md An example of a `destroy` step that specifies initial input, actor, and tenant configurations. This demonstrates a complex destroy operation. ```elixir destroy :delete_post, MyApp.Post, :destroy do initial input(:post) actor result(:get_user) tenant result(:get_organisation, [:id]) end ``` -------------------------------- ### Length of list example Source: https://github.com/ash-project/ash/blob/main/documentation/topics/reference/expressions.md Shows how to get the number of elements in a list using the `length/1` function. ```elixir length([:foo, :bar]) ``` -------------------------------- ### Example Usage of Generic Action Source: https://github.com/ash-project/ash/blob/main/documentation/topics/actions/generic-actions.md Demonstrates calling a generic action `:say_hello` with specific arguments and handling the result. ```elixir action :say_hello, :string do argument :name, :string, allow_nil?: false run fn input, _ -> {:ok, "Hello: #{input.arguments.name}"} end end ``` ```elixir {:ok, greeting} = Resource |> Ash.ActionInput.for_action(:say_hello, %{name: "Alice"}) |> Ash.run_action() IO.puts(greeting) # Output: Hello: Alice ``` -------------------------------- ### Resource change examples Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Resource.md Examples of applying built-in or custom changes to a resource action. ```elixir change relate_actor(:reporter) ``` ```elixir change {MyCustomChange, :foo} ``` -------------------------------- ### Example of custom input configuration Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Resource.md Demonstrates defining a custom input with transformation logic and type constraints. ```elixir custom_input :artist, :struct do transform to: :artist_id, using: &(&1.id) constraints instance_of: Artist end ``` -------------------------------- ### Install Igniter and Create New Phoenix Project with Ash Source: https://github.com/ash-project/ash/blob/main/documentation/tutorials/get-started.md Installs the igniter_new and phx_new archives, then creates a new Phoenix project with Ash and ash_phoenix dependencies. Navigates into the new project directory. ```bash mix archive.install hex phx_new mix archive.install hex igniter_new mix igniter.new helpdesk --install ash,ash_phoenix --with phx.new && cd helpdesk ``` -------------------------------- ### Install Ash & AshPostgres Source: https://github.com/ash-project/ash/blob/main/documentation/topics/development/generators.md Use this command to install Ash and the AshPostgres extension into your current project. ```bash mix igniter.install ash ash_postgres ``` -------------------------------- ### Example forbid_if usage Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Policy.Authorizer.md Examples demonstrating the usage of forbid_if with various checks. ```elixir forbid_if not_logged_in() ``` ```elixir forbid_if actor_attribute_matches_record(:group, :blacklisted_groups) ``` -------------------------------- ### Resource validation example Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Resource.md Example of applying a validation to a resource action. ```elixir validate changing(:email) ``` -------------------------------- ### Create New Project with Ash & AshPostgres Source: https://github.com/ash-project/ash/blob/main/documentation/topics/development/generators.md Generates a new mix project and installs Ash and AshPostgres. ```bash mix archive.install hex igniter_new mix igniter.new my_project --install ash,ash_postgres ``` -------------------------------- ### Calculation argument examples Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Resource.md Examples of defining arguments with default values or nil constraints. ```elixir argument :params, :map do default %{} end ``` ```elixir argument :retries, :integer do allow_nil? false end ``` -------------------------------- ### Example Project Directory Structure Source: https://github.com/ash-project/ash/blob/main/documentation/topics/development/project-structure.md Illustrates a recommended directory layout for an Ash application, showing domains, resources, and supporting modules. ```tree lib/ ├── my_app/ # Your application's main namespace │ ├── accounts.ex # Accounts domain module │ ├── helpdesk.ex # Helpdesk domain module │ │ │ ├── accounts/ # Accounts context │ │ ├── user.ex # User resource │ │ ├── user/ # User resource files │ │ ├── token.ex # Token resource │ │ └── password_helper.ex # Support module │ │ │ └── helpdesk/ # Helpdesk context │ ├── ticket.ex # Ticket resource │ ├── notification.ex # Notification resource │ ├── other_file.ex # Support module │ └── ticket/ # Ticket resource files │ ├── preparations/ │ ├── changes/ │ └── checks/ ``` -------------------------------- ### Custom Aggregate Implementation Example Source: https://github.com/ash-project/ash/blob/main/documentation/topics/resources/aggregates.md Provides an example of a custom aggregate implementation using `AshPostgres.CustomAggregate`. This specific example calculates percentiles using PostgreSQL's `PERCENTILE_CONT` function. ```elixir defmodule PercentileAggregate do @moduledoc false use AshPostgres.CustomAggregate require Ecto.Query @impl true def dynamic(opts, binding) do Ecto.Query.dynamic( [], fragment( "PERCENTILE_CONT(?) WITHIN GROUP (ORDER BY ?)", ^opts[:percentile], field(as(^binding), ^opts[:field]) ) ) end end ``` -------------------------------- ### String split example (default delimiter) Source: https://github.com/ash-project/ash/blob/main/documentation/topics/reference/expressions.md Shows how to split a string into a list of substrings using spaces as the default delimiter with `string_split/1`. ```elixir string_split("hello world") ``` -------------------------------- ### Install Igniter and Create New Project with Ash Source: https://github.com/ash-project/ash/blob/main/documentation/tutorials/get-started.md Installs the igniter.new archive and creates a new Elixir application with Ash as a dependency. Navigates into the new project directory. ```bash mix archive.install hex igniter_new mix igniter.new helpdesk --install ash && cd helpdesk ``` -------------------------------- ### Implement calculation variations Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Resource.md Examples showing module-based implementations, expression-based calculations, and configuration options. ```elixir calculate :full_name, :string, {MyApp.FullName, keys: [:first_name, :last_name]}, load: [:first_name, :last_name] ``` ```elixir calculate :full_name, :string, expr(first_name <> " " <> last_name) ``` ```elixir calculate :full_name, :string, expr(first_name <> " " <> last_name), allow_nil?: false ``` ```elixir calculate :full_name, :string, expr(first_name <> " " <> last_name) do allow_nil? false public? true end ``` -------------------------------- ### String split example (custom delimiter) Source: https://github.com/ash-project/ash/blob/main/documentation/topics/reference/expressions.md Demonstrates splitting a string into a list of substrings using a custom delimiter with `string_split/2`. ```elixir string_split("a,b,c", ",") ``` -------------------------------- ### Resource Setup with Policy Authorizer Source: https://github.com/ash-project/ash/blob/main/documentation/topics/security/policies.md To enable policies for a resource, add the `Ash.Policy.Authorizer` to the resource's authorizers list. ```elixir use Ash.Resource, authorizers: [Ash.Policy.Authorizer] ``` -------------------------------- ### Identity Declaration Examples Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Resource.md Examples of declaring single-field and multi-field identities. ```elixir identity :name, [:name] ``` ```elixir identity :full_name, [:first_name, :last_name] ``` -------------------------------- ### Authorize If Examples Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Policy.Authorizer.md Provides examples of using `authorize_if` with different types of checks, such as checking login status or matching actor attributes to record attributes. ```elixir authorize_if logged_in() ``` ```elixir authorize_if actor_attribute_matches_record(:group, :group) ``` -------------------------------- ### Example usage of create_timestamp Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Resource.md A simple example of adding an inserted_at timestamp to a resource. ```elixir create_timestamp :inserted_at ``` -------------------------------- ### Join Filter Example Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Resource.md Example of applying a join filter to an aggregate path. ```elixir join_filter [:comments, :author], expr(active == true) ``` -------------------------------- ### Example Notifier Implementation Source: https://github.com/ash-project/ash/blob/main/documentation/topics/resources/notifiers.md Implement a custom notifier by defining the `notify/1` callback. This example logs a message when a resource is created, checking if an actor is present. ```elixir defmodule ExampleNotifier do use Ash.Notifier def notify(%Ash.Notifier.Notification{resource: resource, action: %{type: :create}, actor: actor}) do if actor do Logger.info("#{actor.id} created a #{resource}") else Logger.info("A non-logged in user created a #{resource}") end end end ``` -------------------------------- ### Count Aggregate Examples Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Resource.md Examples of using count aggregates with relationships or direct resource references. ```elixir count :assigned_ticket_count, :assigned_tickets do filter [active: true] end ``` ```elixir count :matching_profiles_count, Profile do filter expr(name == parent(name)) end ``` -------------------------------- ### String join example (with delimiter) Source: https://github.com/ash-project/ash/blob/main/documentation/topics/reference/expressions.md Demonstrates joining a list of strings with a specified delimiter, while ignoring nil values, using `string_join/2`. ```elixir string_join(["a", "b", "c"], ", ") ``` -------------------------------- ### Policy Breakdown Example (Full) Source: https://github.com/ash-project/ash/blob/main/documentation/topics/security/policies.md A sample policy breakdown output showing the status of various authorization checks, including detailed help text. ```text Policy Breakdown A check status of `?` implies that the solver did not need to determine that check. Some checks may look like they failed when in reality there was no need to check them. Look for policies with `✘` and `✓` in check statuses. A check with a `⬇` means that it didn't determine if the policy was authorized or forbidden, and so moved on to the next check. `🌟` and `⛔` mean that the check was responsible for producing an authorized or forbidden (respectively) status. If no check results in a status (they all have `⬇`) then the policy is assumed to have failed. In some cases, however, the policy may have just been ignored, as described above. Admins and managers can create posts | ⛔: authorize if: actor.admin == true | ✘ | ⬇ authorize if: actor.manager == true | ✘ | ⬇ ``` -------------------------------- ### Reactor Inputs DSL Example 1 Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Reactor.md Use `inputs` to specify the data that an action will receive. This example shows how to map results from other steps and direct inputs. ```elixir inputs %{ author: result(:get_user), title: input(:title), body: input(:body) } ``` -------------------------------- ### Example of a primary destroy action Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Resource.md A concrete example of defining a primary destroy action. ```elixir destroy :destroy do primary? true end ``` -------------------------------- ### Example Implications of Tenant-Scoped and Global Identities Source: https://github.com/ash-project/ash/blob/main/documentation/topics/advanced/multitenancy.md Illustrates the behavior of tenant-scoped and globally unique identities. The first two examples show valid creations of users with the same email in different tenants. The subsequent examples demonstrate how attempting to create users with the same globally unique username across tenants will result in an error. ```elixir # These are valid because they're in different tenants User |> Ash.Changeset.for_create(:create, %{email: "fred@example.com"}) |> Ash.Changeset.set_tenant(1) |> Ash.create!() User |> Ash.Changeset.for_create(:create, %{email: "fred@example.com"}) |> Ash.Changeset.set_tenant(2) |> Ash.create!() # This would fail because usernames are global User |> Ash.Changeset.for_create(:create, %{username: "fred"}) |> Ash.Changeset.set_tenant(1) |> Ash.create!() User |> Ash.Changeset.for_create(:create, %{username: "fred"}) |> Ash.Changeset.set_tenant(2) |> Ash.create!() # Error: username already taken ``` -------------------------------- ### Global Changes with 'on' and 'where' Source: https://github.com/ash-project/ash/blob/main/documentation/topics/resources/changes.md An example demonstrating global changes with specific actions defined by `on` and conditional execution using `where`. ```elixir changes do change relate_actor(:owner) change set_attribute(:committed_at, &DateTime.utc_now/0) change optimistic_lock(:version), on: [:create, :update, :destroy] change {Slugify, [attribute: :foo]}, on: :create end ``` -------------------------------- ### Install Hex Archives Source: https://github.com/ash-project/ash/blob/main/documentation/topics/development/generators.md Archives must be installed to be used. This only needs to be done once per Elixir version. ```elixir mix archive.install hex igniter_new mix archive.install hex phx_new ``` -------------------------------- ### Validation examples Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Resource.md Specific examples of validation declarations using modules or built-in functions. ```elixir validate {Mod, [foo: :bar]} ``` ```elixir validate present([:first_name, :last_name], at_least: 1) ``` -------------------------------- ### Create Phoenix Project with Ash & AshPostgres Source: https://github.com/ash-project/ash/blob/main/documentation/topics/development/generators.md Generates a new Phoenix project with Ash, AshPostgres, and AshPhoenix installed. ```bash mix igniter.new my_project --install ash,ash_postgres,ash_phoenix --with phx.new ``` -------------------------------- ### Install Igniter and Add Ash to Existing Project Source: https://github.com/ash-project/ash/blob/main/documentation/tutorials/get-started.md Installs the igniter_new archive and adds Ash to an existing Elixir project. ```bash mix archive.install hex igniter_new mix igniter.install ash ``` -------------------------------- ### Policy Breakdown Example (No Help Text) Source: https://github.com/ash-project/ash/blob/main/documentation/topics/security/policies.md A condensed policy breakdown output without the explanatory help text, useful for cleaner logs. ```text Policy Breakdown Admins and managers can create posts | ⛔: authorize if: actor.admin == true | ✘ | ⬇ authorize if: actor.manager == true | ✘ | ⬇ ``` -------------------------------- ### Reactor Inputs DSL Example 2 Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Reactor.md A more concise way to define inputs using keyword lists, mapping results from other steps. ```elixir inputs(author: result(:get_user)) ``` -------------------------------- ### Get list element example Source: https://github.com/ash-project/ash/blob/main/documentation/topics/reference/expressions.md Retrieves an element from a list at a specific zero-based index using the `at/2` function. ```elixir at(list, 1) ``` -------------------------------- ### Call a Create Action Source: https://github.com/ash-project/ash/blob/main/documentation/topics/actions/create-actions.md Demonstrates how to create a new record using the `:open` action defined previously. It prepares a changeset and then creates the record. ```elixir Ticket |> Ash.Changeset.for_create(:open, %{title: "Need help!"}) |> Ash.create!() ``` -------------------------------- ### Get path example Source: https://github.com/ash-project/ash/blob/main/documentation/topics/reference/expressions.md Illustrates how to access nested values within data structures using the `get_path/2` function, which is the underlying mechanism for chained attribute access. ```elixir get_path(value, ["foo", "bar"]) ``` -------------------------------- ### Define a Resource Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Domain.md Declare a resource within the `resources` block. This example shows a basic resource declaration. ```elixir resource Foo ``` -------------------------------- ### Example of Generic Action Implementation Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Resource.md Implementation of a generic action that returns an array of strings based on provided arguments. ```elixir action :top_user_emails, {:array, :string} do argument :limit, :integer, default: 10, allow_nil?: false run fn input, context -> with {:ok, top_users} <- top_users(input.arguments.limit) do {:ok, Enum.map(top_users, &(&1.email))} end end end ``` -------------------------------- ### Getting Upsert Action Metadata Source: https://github.com/ash-project/ash/blob/main/documentation/topics/actions/create-actions.md This example shows how to retrieve the `:upsert_action` metadata from a returned record to determine if an upsert resulted in an insert or an update. This is supported on PostgreSQL 17+ when using `MERGE`. ```elixir [record] = Ash.create!(changeset, upsert?: true, upsert_identity: :unique_email, return_records?: true) Ash.Resource.get_metadata(record, :upsert_action) ``` -------------------------------- ### Create and Update Posts with Tags Source: https://github.com/ash-project/ash/blob/main/usage-rules/relationships.md Examples of creating a post with new tags and updating a post to replace its existing tags using relationship management. ```elixir # Creating a post with tags MyDomain.create_post!(%{ title: "New Post", body: "Content here...", tags: [%{name: "elixir"}, %{name: "ash"}] # Creates new tags }) # Updating a post to replace its tags MyDomain.update_post!(post, %{ tags: [tag1.id, tag2.id] # Replaces tags with existing ones by ID }) ``` -------------------------------- ### String join example (no delimiter) Source: https://github.com/ash-project/ash/blob/main/documentation/topics/reference/expressions.md Shows how to concatenate a list of strings into a single string, ignoring any nil values, using `string_join/1`. ```elixir string_join(["a", nil, "b"]) ``` -------------------------------- ### Define a specific attribute Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Resource.md Example of defining an attribute with specific configuration options like allow_nil. ```elixir attribute :name, :string do allow_nil? false end ``` -------------------------------- ### Create config/config.exs Source: https://github.com/ash-project/ash/blob/main/documentation/topics/advanced/manual-installation.md Initial configuration for Spark formatter settings. ```elixir import Config config :spark, formatter: [remove_parens?: true] ``` -------------------------------- ### Define has_many relationships Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Resource.md Example of defining has_many relationships with explicit destination attributes. ```elixir relationships do has_many :posts, MyApp.Post do destination_attribute :author_id end has_many :composite_key_posts, MyApp.CompositeKeyPost do destination_attribute :author_id end end ``` -------------------------------- ### Define Resource Aggregates Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Resource.md Example of declaring a count aggregate within an aggregates block. ```elixir aggregates do count :assigned_ticket_count, :reported_tickets do filter [active: true] end end ``` -------------------------------- ### Define belongs_to relationships Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Resource.md Example of defining multiple belongs_to relationships within a resource. ```elixir relationships do belongs_to :post, MyApp.Post do primary_key? true end belongs_to :category, MyApp.Category do primary_key? true end end ``` -------------------------------- ### Define a primary read action Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Resource.md Example of defining a read action named :read_all marked as the primary action. ```elixir read :read_all do primary? true end ``` -------------------------------- ### Comprehensive Example Reactor Source: https://github.com/ash-project/ash/blob/main/documentation/topics/advanced/reactor.md Demonstrates a complete `Ash.Reactor` definition with multiple input definitions and sequential actions for creating a customer, retrieving a plan, processing payment, and creating a subscription. ```elixir defmodule ExampleReactor do use Ash.Reactor ash do default_domain ExampleDomain end input :customer_name input :customer_email input :plan_name input :payment_nonce create :create_customer, Customer do inputs %{name: input(:customer_name), email: input(:customer_email)} end read_one :get_plan, Plan, :get_plan_by_name do inputs %{name: input(:plan_name)} fail_on_not_found? true end action :take_payment, PaymentProvider do inputs %{ nonce: input(:payment_nonce), amount: result(:get_plan, [:price]) } end create :subscription, Subscription do inputs %{ plan_id: result(:get_plan, [:id]), payment_provider_id: result(:take_payment, :id) } end end ``` -------------------------------- ### Define resource attributes Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Resource.md Example of declaring various attributes, primary keys, and timestamps within an attributes block. ```elixir attributes do uuid_primary_key :id attribute :first_name, :string do allow_nil? false end attribute :last_name, :string do allow_nil? false end attribute :email, :string do allow_nil? false constraints [ match: ~r/^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$/ ] end attribute :type, :atom do constraints [ one_of: [:admin, :teacher, :student] ] end create_timestamp :inserted_at update_timestamp :updated_at end ``` -------------------------------- ### Define a has_one relationship with custom attributes Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Resource.md Example of a has_one relationship configured with specific source and destination attributes. ```elixir # In a resource called `Word` has_one :dictionary_entry, DictionaryEntry do source_attribute :text destination_attribute :word_text end ``` -------------------------------- ### Define Resource Action Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Domain.md Use the `define` keyword within a resource to define a function. This example defines a `get_user_by_id` function with specific arguments and action. ```elixir define :get_user_by_id, action: :get_by_id, args: [:id], get?: true ``` -------------------------------- ### Define a belongs_to relationship Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Resource.md Example of defining a belongs_to relationship with custom source and destination attributes. ```elixir # In a resource called `Word` belongs_to :dictionary_entry, DictionaryEntry do source_attribute :text, destination_attribute :word_text end ``` -------------------------------- ### Define belongs_to and many_to_many relationships Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Resource.md Example of combining a belongs_to relationship with a many_to_many relationship using a join resource. ```elixir relationships do belongs_to :author, MyApp.Author many_to_many :categories, MyApp.Category do through MyApp.PostCategory destination_attribute_on_join_resource :category_id source_attribute_on_join_resource :post_id end end ``` -------------------------------- ### Create Domain and Resource Files Source: https://github.com/ash-project/ash/blob/main/documentation/tutorials/get-started.md Creates the necessary directories and files for a new Ash domain and resource. ```bash mkdir -p lib/helpdesk/support && \ touch $_/ticket.ex && \ touch lib/helpdesk/support.ex ``` -------------------------------- ### Introspect Pipelines Source: https://github.com/ash-project/ash/blob/main/documentation/topics/actions/actions.md Provides examples of how to inspect pipelines at runtime using `Ash.Resource.Info`. This allows querying for all pipelines on a resource or retrieving a specific pipeline by name. ```elixir # List all pipelines on a resource Ash.Resource.Info.pipelines(MyResource) # Get a specific pipeline by name Ash.Resource.Info.pipeline(MyResource, :audited) ``` -------------------------------- ### Handle Action Arguments: Reads vs. Creates Source: https://github.com/ash-project/ash/blob/main/documentation/topics/resources/code-interfaces.md Understand how arguments differ for read actions (query as last opt) versus update/destroy actions (record/changeset as first arg). Optional arguments for options and action input are also shown. ```elixir # Because the 3rd argument is a keyword list, we use it as options Accounts.register_user(username, password, [tenant: "organization_22"]) # Because the 3rd argument is a map, we use it as action input Accounts.register_user(username, password, %{key: "val"}) # When all arguments are provided it is unambiguous Accounts.register_user(username, password, %{key: "val"}, [tenant: "organization_22"]) ``` -------------------------------- ### Create config/prod.exs Source: https://github.com/ash-project/ash/blob/main/documentation/topics/advanced/manual-installation.md Configuration specific to the production environment. ```elixir import Config ``` -------------------------------- ### Example: Forbid if not logged in Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Policy.Authorizer.md An example of using `forbid_if` with a custom function `not_logged_in()` to prevent unauthorized access. ```elixir forbid_if not_logged_in() ``` -------------------------------- ### Example: Forbid unless logged in Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Policy.Authorizer.md An example of using `forbid_unless` with `logged_in()` to ensure authorization proceeds only if the actor is logged in. ```elixir forbid_unless logged_in() ``` -------------------------------- ### Example: Authorize unless not logged in Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Policy.Authorizer.md An example of using `authorize_unless` with `not_logged_in()` to allow authorization to proceed if the actor is not logged in. ```elixir authorize_unless not_logged_in() ``` -------------------------------- ### Configure Formatter for .formatter.exs Source: https://github.com/ash-project/ash/blob/main/documentation/topics/advanced/manual-installation.md Sets up the formatter with Spark.Formatter and imports the reactor dependency. ```elixir plugins: [Spark.Formatter], import_deps: [:reactor] ``` -------------------------------- ### Create .formatter.exs Source: https://github.com/ash-project/ash/blob/main/documentation/topics/advanced/manual-installation.md Initial configuration for the Elixir formatter, including input files and the Spark.Formatter plugin. ```elixir # Used by "mix format" [ inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"], plugins: [Spark.Formatter] ] ``` -------------------------------- ### Manual Create Action Implementation Source: https://github.com/ash-project/ash/blob/main/documentation/topics/actions/manual-actions.md Implement a custom create action by defining a module that adopts Ash.Resource.ManualCreate. The `create/3` function should return `{:ok, record}` on success or `{:error, error}` on failure. ```elixir create :special_create do manual MyApp.DoCreate end # The implementation defmodule MyApp.DoCreate do use Ash.Resource.ManualCreate def create(changeset, _, _) do record = create_the_record(changeset) {:ok, record} # An `{:error, error}` tuple should be returned if something failed end end ``` -------------------------------- ### Use Calculations in Ash Combination Queries Source: https://github.com/ash-project/ash/blob/main/documentation/topics/advanced/combination-queries.md This example searches for users by name or email similarity to 'fred', returning the top 10 matches for each, sorted by match score. It showcases using `calc/2` within `base/1` and `union/1` to define and sort by `match_score`. ```elixir query = "fred" User |> Ash.Query.filter(active == true) |> Ash.Query.combination_of([ Ash.Query.Combination.base( filter: expr(trigram_similarity(user_name, ^query) >= 0.5), calculations: %{ match_score: calc(trigram_similarity(user_name, ^query), type: :float) }, sort: [ {calc(trigram_similarity(user_name, ^query), type: :float), :desc} ], limit: 10 ), Ash.Query.Combination.union( filter: expr(trigram_similarity(email, ^query) >= 0.5), calculations: %{ match_score: calc(trigram_similarity(email, ^query), type: :float) }, sort: [ {calc(trigram_similarity(email, ^query), type: :float), :desc} ], limit: 10 ) ]) |> Ash.read!() ``` -------------------------------- ### Expression Calculations Examples Source: https://github.com/ash-project/ash/blob/main/usage-rules/calculations.md Use Ash expressions for calculations that can be pushed down to the data layer. Examples include string concatenation, math operations, and date manipulation. ```elixir calculations do # Simple string concatenation calculate :full_name, :string, expr(first_name <> " " <> last_name) # Math operations calculate :total_with_tax, :decimal, expr(amount * (1 + tax_rate)) # Date manipulation calculate :days_since_created, :integer, expr( date_diff(^now(), inserted_at, :day) ) end ``` -------------------------------- ### Define CRUD Actions in Ash Resource Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Resource.md Example of defining various CRUD actions within an actions block, including custom changes, filters, and soft deletes. ```elixir actions do create :signup do argument :password, :string argument :password_confirmation, :string validate confirm(:password, :password_confirmation) change {MyApp.HashPassword, []} # A custom implemented Change end read :me do # An action that auto filters to only return the user for the current user filter [id: actor(:id)] end update :update do accept [:first_name, :last_name] end destroy do change set_attribute(:deleted_at, &DateTime.utc_now/0) # This tells it that even though this is a delete action, it # should be treated like an update because `deleted_at` is set. # This should be coupled with a `base_filter` on the resource # or with the read actions having a `filter` for `is_nil: :deleted_at` soft? true end end ``` -------------------------------- ### Example SQL for Fully Atomic Update Source: https://github.com/ash-project/ash/blob/main/documentation/topics/actions/update-actions.md Illustrates the SQL generated for a fully atomic update, showing how `name` and `slug` are updated in a single database operation. ```sql UPDATE table SET name = name || $1, slug = CASE WHEN name = name || $1 THEN slug ELSE slugify(name || $1) END WHERE id = $2 ``` -------------------------------- ### Example of a Single Error Representing Multiple Underlying Errors Source: https://github.com/ash-project/ash/blob/main/documentation/topics/development/error-handling.md This example shows how Ash can raise a single top-level error (Ash.Error.Invalid) that encapsulates multiple underlying validation issues. ```elixir AshExample.Representative |> Ash.Changeset.for_create(:create, %{employee_id: "the best"}) |> Ash.create!() ** (Ash.Error.Invalid) Invalid Error * employee_id: must be absent. * first_name, last_name: at least 1 must be present. ``` -------------------------------- ### Call a Read Action Source: https://github.com/ash-project/ash/blob/main/documentation/topics/actions/read-actions.md Demonstrates the basic syntax for calling a read action using Ash.Query.for_read and Ash.read!. ```elixir Resource |> Ash.Query.for_read(:action_name, %{argument: :value}, ...opts) |> Ash.read!() ``` -------------------------------- ### Reactor Action Inputs and Sequencing Source: https://github.com/ash-project/ash/blob/main/documentation/topics/advanced/reactor.md Illustrates defining inputs, reading related data, creating new records, and updating existing ones within a Reactor, demonstrating dependency between steps using `wait_for` and referencing results. ```elixir input :blog_title input :blog_body input :author_email read :get_author, MyBlog.Author, :get_author_by_email do inputs %{email: input(:author_email)} end create :create_post, MyBlog.Post, :create do inputs %{ title: input(:blog, [:title]), body: input(:blog, [:body]), author_id: result(:get_author, [:email]) } end update :author_post_count, MyBlog.Author, :update_post_count do wait_for :create_post initial result(:get_author) end return :create_post ``` -------------------------------- ### reactor.read_one.wait_for Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Reactor.md Wait for a named step to complete before allowing the current step to start. ```APIDOC ## reactor.read_one.wait_for ### Description Wait for the named step to complete before allowing this one to start. Desugars to `argument :_, result(step_to_wait_for)` ### Arguments #### names - **names** ( atom | list(atom) ) - Required - The name of the step to wait for. ### Options #### description - **description** (String.t) - Optional - An optional description. ``` -------------------------------- ### Dynamic Loading and Filtering with 'Get By' Functions Source: https://github.com/ash-project/ash/blob/main/documentation/topics/resources/code-interfaces.md Demonstrates how to use the 'load' and 'query' options with 'get_by' functions to dynamically fetch related data and apply filters. ```elixir # Load relationships MyApp.Dashboards.get_dashboard_group_by_id!(id, load: [students: [:user]]) # Apply additional filters MyApp.Dashboards.get_dashboard_group_by_id!(id, query: [filter: [status: :active]]) # Combine both MyApp.Dashboards.get_dashboard_group_by_id!(id, load: [students: [:user]], query: [filter: [status: :active]] ) ``` -------------------------------- ### reactor.load.wait_for Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Reactor.md Waits for the named step to complete before allowing the current one to start. ```APIDOC ## reactor.load.wait_for ### Description Wait for the named step to complete before allowing this one to start. Desugars to `argument :_, result(step_to_wait_for)` ### Examples ```elixir wait_for :create_user ``` ### Arguments - **names** (atom | list(atom)) - Required - The name of the step to wait for. ``` -------------------------------- ### Call an Update Action Source: https://github.com/ash-project/ash/blob/main/documentation/topics/actions/update-actions.md Demonstrates how to create a changeset for an update action and then perform the update. ```elixir ticket # providing an initial ticket to close |> Ash.Changeset.for_update(:close, %{close_reason: "I figured it out."}) ``` ```elixir |> Ash.update!() ``` -------------------------------- ### String length example Source: https://github.com/ash-project/ash/blob/main/documentation/topics/reference/expressions.md Returns the length of a given string using the `string_length/1` function. ```elixir string_length(string_field) ``` -------------------------------- ### String downcasing example Source: https://github.com/ash-project/ash/blob/main/documentation/topics/reference/expressions.md Demonstrates converting a string to lowercase using the `string_downcase/1` function. ```elixir string_downcase(string_field) ``` -------------------------------- ### Using a Custom Preparation Source: https://github.com/ash-project/ash/blob/main/documentation/topics/resources/preparations.md Incorporate a custom preparation into a resource by referencing its module and passing necessary options. ```elixir prepare {MyApp.Preparations.Top5, attribute: :foo} ``` -------------------------------- ### Custom Preparation Module Source: https://github.com/ash-project/ash/blob/main/documentation/topics/resources/preparations.md Define a custom preparation module by implementing `init/1` for option transformation and validation, and `prepare/3` for the preparation logic. ```elixir defmodule MyApp.Preparations.Top5 do use Ash.Resource.Preparation @impl true def init(opts) do if is_atom(opts[:attribute]) do {:ok, opts} else {:error, "attribute must be an atom!"} end end @impl true def prepare(query, opts, _context) do attribute = opts[:attribute] query |> Ash.Query.sort([{attribute, :desc}]) |> Ash.Query.limit(5) end end ``` -------------------------------- ### Option Merging Example Source: https://github.com/ash-project/ash/blob/main/documentation/topics/resources/code-interfaces.md Illustrates how default and client-provided options are merged. Client options override defaults, but `:load` options are combined, resulting in a comprehensive set of applied loads. ```elixir # With default_options: [load: [:profile], authorize?: true] MyApp.get_user(123, load: [:posts], authorize?: false) # Results in: [load: [:profile, :posts], authorize?: false] ``` -------------------------------- ### Define a step to create a resource Source: https://github.com/ash-project/ash/blob/main/documentation/dsls/DSL-Ash.Reactor.md Use `create` to define a step that calls a create action on a specified resource. This step supports various configurations for inputs, actors, tenants, and undo behavior. ```elixir create name, resource, action \\ nil ``` ```elixir create :create_post, MyApp.Post, :create do inputs %{ title: input(:post_title), author_id: result(:get_user, [:id]) } actor result(:get_user) tenant result(:get_organisation, [:id]) end ``` -------------------------------- ### Create config/dev.exs Source: https://github.com/ash-project/ash/blob/main/documentation/topics/advanced/manual-installation.md Configuration specific to the development environment. ```elixir import Config config :ash, policies: [show_policy_breakdowns?: true] ``` -------------------------------- ### String trim example Source: https://github.com/ash-project/ash/blob/main/documentation/topics/reference/expressions.md Removes unicode whitespace from the beginning and end of a string using `string_trim/1`. ```elixir string_trim(string_field) ```