chore: docs/ci work

This commit is contained in:
Zach Daniel 2022-04-05 03:59:34 -04:00
parent a012287c3b
commit 84ed398980
11 changed files with 36 additions and 94 deletions

View file

@ -103,7 +103,6 @@ locals_without_parens = [
prepare: 1,
prepare: 2,
primary?: 1,
primary_actions?: 1,
primary_key?: 1,
private?: 1,
publish: 2,

View file

@ -2,18 +2,21 @@
The first step is to decide if you're building a phoenix application or not. Phoenix is an extremely high quality web framework, and is the suggested pairing with Ash if you expect to be building a front end, or an API. For this guide, we assume that elixir has already been installed.
## Installing Phoenix
## Installing With Phoenix
First, install the phoenix installation archive.
Install the Phoenix installation archive and then create a new Phoenix application. Be sure to look over the options available with `mix help phx.new`, and visit the phoenix [Phoenix Documentation](https://www.phoenixframework.org/) for more information.
```bash
mix archive.install hex phx_new
mix phx.new <my_app> --live
```
Then, create a new phx application. Generally, we suggest installing liveview as well, via the `--live` flag. See the phoenix [Phoenix Documentation](https://www.phoenixframework.org/) fore more information.
## Installing Without Phoenix
Create a new application. Be sure to look aver the options available with `mix help new`.
```bash
mix phx.new <my_app> --live
mix new <my_app>
```
## Adding Ash
@ -21,7 +24,7 @@ mix phx.new <my_app> --live
1. First off, add Ash as a dependency. In `mix.exs`, add
`{:ash, "~> 1.52.0-rc.0"}` to your dependencies.
2. Next, add an API. To start, a simple choice for naming your first API is a good name for the "core" of your application. For example, a help-desk application called "AwesomeDesk" might start with an API module called `AwesomeDesk.Tickets`. Create `lib/my_app/my_api/my_api.ex`, with the following contents:
2. Next, add an API. To start, a simple choice for naming your first API is a good name for the "core" of your application. For example, a help-desk application called "AwesomeDesk" might start with an API module called `AwesomeDesk.Tickets`. Create an `lib/my_app/my_api/my_api.ex`, with the following contents:
```elixir
defmodule MyApp.MyApi do
@ -81,7 +84,7 @@ mix phx.new <my_app> --live
end
```
6. Add your resource to the registry that you created
6. Add your [resource](../concepts/resource.md) to the registry that you created
```elixir
@ -90,7 +93,9 @@ mix phx.new <my_app> --live
end
```
7. You can't do anything without adding [actions](../concepts/actions.md)
8. Add some actions to your resource
9. Try it out. Currently, your resource won't do much. The `defaults` option creates
7. Resources are static descriptions of behavior, and don't do anything on their own. To give them functionality, we must first add [actions](../concepts/actions.md).
8.
9. can't do anything **without** adding [actions](../concepts/actions.md). So to pro
10. Add some actions to your resource
11. Try it out. Currently, your resource won't do much. The `defaults` option creates
four available "actions"

View file

View file

View file

@ -14,4 +14,4 @@ end
### Primary Actions
Primary actions have been simplified for 2.0.0. If there was a single action of a given type before, it would have been marked as `primary?` automatically. Now, `primary?` actions are fully optional, although you may still want to configure them. Certain things like [managing relationships](managing_relationships.md) can be much simpler when paired with primary actions. For a fully explicit experience everywhere, however, you may want to skip primary actions altogether. To make sure your application behaves the same, go to each of your resources and check to see if they only have one action of each type. If they do, mark that single action as `primary?`.
Primary actions have been simplified for 2.0.0. If there was a single action of a given type before, it would have been marked as `primary?` automatically. Now, `primary?` actions are fully optional, although you may still want to configure them. Certain things like [managing relationships](managing_relationships.md) can be much simpler when paired with primary actions. For a fully explicit experience everywhere, however, you may want to skip primary actions altogether. To make sure your application behaves the same, go to each of your resources and check to see if they only have one action of each type. If they do, mark that single action as `primary?`. Additionally, the `primary_actions?` option has been removed now that all primary actions are explicit.

View file

@ -46,7 +46,7 @@ defmodule Ash.DocIndex do
end)
@impl Ash.DocIndex
def guides() do
def guides do
@files
end
end
@ -56,8 +56,7 @@ defmodule Ash.DocIndex do
def to_name(string) do
string
|> String.split(~r/[-_]/, trim: true)
|> Enum.map(&String.capitalize/1)
|> Enum.join(" ")
|> Enum.map_join(" ", &String.capitalize/1)
end
def to_path(string) do

View file

@ -553,29 +553,6 @@ defmodule Ash.Resource.Dsl do
type, as long as they have different names. This is the primary mechanism for customizing
your resources to conform to your business logic. It is normal and expected to have
multiple actions of each type in a large application.
## Primary actions
If you have multiple actions of the same type, one of them must be designated as the
primary action for that type, via the `primary?` option. This tells the ash what to do
if an action of that type is requested, but no specific action name is given. This is how
many relationship changes will happen, by utilizing the primary actions. For this reason,
** when defining actions, you usually want to ensure that the primary action takes no required
arguments **. Without that, relationship changes to your resources might fail due to missing
arguments. This does, however, allow you to customize exactly how related entities are read/
created.
## Turning primary actions off
If you want an extremely explicit experience with actions, you can specify the following option:
```elixir
primary_actions? false
```
This will prevent Ash from adding a default implementation of each action type, as well as cause any calls
to `Ash.Resource.Info.primary_action/2` to raise an error. This is experimental, but any errors raised in appropriate
places can be addressed, just report them as issues.
""",
imports: [
Ash.Resource.Change.Builtins,
@ -584,16 +561,6 @@ defmodule Ash.Resource.Dsl do
Ash.Filter.TemplateHelpers
],
schema: [
primary_actions?: [
type: {:in, [true, false, :only_read]},
default: true,
doc: """
Causes any calls to `Ash.Resource.Info.primary_action/2` to raise an error. This is experimental, but any errors raised in appropriate
places can be addressed, just report them as issues. Use `:read_only` to allow primary actions only for reads.
This can be useful to avoid constantly having to provide the basic `read` action of a given resource, when you need
to do things like loading data.
"""
],
defaults: [
type: {:list, {:in, [:create, :read, :update, :destroy]}},
doc: """

View file

@ -423,37 +423,15 @@ defmodule Ash.Resource.Info do
@spec primary_action(Ash.Resource.t(), Ash.Resource.Actions.action_type()) ::
Ash.Resource.Actions.action() | nil
def primary_action(resource, type) do
primary_actions? = primary_actions?(resource)
cond do
primary_actions? == :only_read && type != :read ->
raise "Cannot use primary #{type} actions with resource: #{inspect(resource)}, because `primary_actions?` is set to `:only_read`"
!primary_actions? ->
raise "Cannot use primary actions with resource: #{inspect(resource)}, because `primary_actions?` is set to `false`"
true ->
resource
|> actions()
|> Enum.filter(&(&1.type == type))
|> case do
[action] -> action
actions -> Enum.find(actions, & &1.primary?)
end
resource
|> actions()
|> Enum.filter(&(&1.type == type))
|> case do
[action] -> action
actions -> Enum.find(actions, & &1.primary?)
end
end
@doc "Returns the value of the primary_actions? configuration"
@spec primary_actions?(Ash.Resource.t()) :: boolean | :only_read
def primary_actions?(resource) do
Extension.get_opt(
resource,
[:actions],
:primary_actions?,
true
)
end
@doc "Returns the configured default actions"
@spec default_actions(Ash.Resource.t()) :: list(:create | :read | :update | :destroy)
def default_actions(resource) do

View file

@ -12,8 +12,6 @@ defmodule Ash.Resource.Transformers.ValidatePrimaryActions do
@extension Ash.Resource.Dsl
def transform(resource, dsl_state) do
primary_actions? = Ash.Resource.Info.primary_actions?(resource)
dsl_state = add_defaults(dsl_state, resource)
dsl_state
@ -40,23 +38,19 @@ defmodule Ash.Resource.Transformers.ValidatePrimaryActions do
)}}
{type, actions}, {:ok, dsl_state} ->
if primary_actions? && !(primary_actions? == :only_read && type != :read) do
case Enum.count_until(actions, & &1.primary?, 2) do
2 ->
{:halt,
{:error,
DslError.exception(
module: resource,
message:
"Multiple actions of type #{type} configured as `primary?: true`, but only one action per type can be the primary",
path: [:actions, type]
)}}
case Enum.count_until(actions, & &1.primary?, 2) do
2 ->
{:halt,
{:error,
DslError.exception(
module: resource,
message:
"Multiple actions of type #{type} configured as `primary?: true`, but only one action per type can be the primary",
path: [:actions, type]
)}}
_ ->
{:cont, {:ok, dsl_state}}
end
else
{:cont, {:ok, dsl_state}}
_ ->
{:cont, {:ok, dsl_state}}
end
end)
end

View file

@ -238,7 +238,7 @@ defmodule Ash.ElixirSense.PluginTest do
result = suggestions(buffer, cursor)
labels = result |> Enum.map(& &1.label) |> Enum.sort()
assert labels == ["create", "defaults", "destroy", "primary_actions?", "read", "update"]
assert labels == ["create", "defaults", "destroy", "read", "update"]
end
test "suggesting available options and entities" do