# Backwards Compatibility Config
All of these configurations are potentially breaking changes when applied
to your application. However, we *highly* encourage setting as many of
them as possible. In 4.0, some will be removed entirely, and any that remain
will have their defaults changed to the new value.
The ash installer automatically sets all of these.
## allow_forbidden_field_for_relationships_by_default?
```elixir
config :ash, allow_forbidden_field_for_relationships_by_default?: true
```
### Old Behavior
Loaded relationships that produced a `Forbidden` error would fail the entire
request. i.e in `Ash.load(post, [:comments, :author])`, if `author` returned
a `Forbidden` error, the entire request would fail with a forbidden error.
### New Behavior
Now the relationships that produced a forbidden error are instead populated
with `%Ash.ForbiddenField{}`.
## include_embedded_source_by_default?
```elixir
config :ash, include_embedded_source_by_default?: false
```
### Old Behavior
When working with embedded types, the `__source__` constraint is populated with
the original changeset. This can be very costly in terms of memory when working with
large sets of embedded resources.
### New Behavior
Now, the source is only included when you say `constraints: [include_source?: true]` on
the embedded resource's usage.
## show_keysets_for_all_actions?
```elixir
config :ash, show_keysets_for_all_actions?: false
```
### Old Behavior
For all actions, the records would be returned with `__metadata__.keyset` populated
with a keyset computed for the `sort` that was used to produce those records. This
is expensive as it requires loading all things that are used by the sort.
### New Behavior
Only when actually performing keyset pagination will the `__metadata__.keyset` be
computed.
## default_page_type
```elixir
config :ash, default_page_type: :keyset
```
### Old Behavior
When an action supports `offset` and `keyset` pagination, and a page is requested
with only `limit` set, i.e `page: [limit: 10]`, you would get back an `%Ash.Page.Offset{}`.
### New Behavior
Now we will return a `%Ash.Page.Keyset{}` choosing it whenever it is ambiguous.
You can always force returning an `%Ash.Page.Offset{}` by providing the offset option,
i.e `page: [offset: 0]`
## policies.no_filter_static_forbidden_reads?
```elixir
config :ash, policies: [no_filter_static_forbidden_reads?: false]
```
### Old Behavior
On read action policies, we can often tell statically that they cannot pass, for example:
```elixir
policy action_type(:read) do
authorize_if actor_attribute_equals(:active, true)
end
```
In these cases, you would get an `Ash.Error.Forbidden`, despite the fact that the
default `access_type` for a policy is `:filter`. If you instead had:
```elixir
policy action_type(:read) do
authorize_if expr(private == false)
end
```
You would get a filter. This made it difficult to predict when you would get a forbidden
error and when the query results would be filtered.
### New Behavior
Now, we always filter the query even if we know statically that the request would be
forbidden. For example the following policy:
```elixir
policy action_type(:read) do
authorize_if actor_attribute_equals(:active, true)
end
```
would yield `filter: false`. This makes the behavior consistent and predictable.
You can always annotate that a given policy should result in a forbidden error
by setting `access_type :strict` in the policy.
## keep_read_action_loads_when_loading?
```elixir
config :ash, keep_read_action_loads_when_loading?: false
```
### Old Behavior
If you had an action with a preparation, or a global preparation that loaded data, i.e
```elixir
prepare build(load: :comments)
```
this wold be applied when using `Ash.load`, because we build a query for the primary
read action as a basis for loading data. This could be expensive because now you are always
loading `:comments` even if you only intended to load something else, and could also be
unpredictable because it could "overwrite" the already loaded `comments` on the data you
passed in.
### New Behavior
When using `Ash.load` *only* the explicitly provided load statement is applied.
## default_actions_require_atomic?
```elixir
config :ash, default_actions_require_atomic?: true
```
### Old Behavior
When building actions like so: `defaults [:read, create: :*, update: :*]` the default
action is generated with `require_atomic? false`. This could make it difficult to spot
actions that cannot safely be done asynchronously.
### New Behavior
The default generated actions are generated with `require_atomic? true`
## read_action_after_action_hooks_in_order?
```elixir
config :ash, read_action_after_action_hooks_in_order?: true
```
### Old Behavior
In 3.0, we modified hooks on changesets to always be added in order instead of in
reverse order. This was missed for `Ash.Query`. Meaning if you had something like this:
```elixir
read :read do
prepare fn query, _ ->
Ash.Query.after_action(query, fn query, results ->
IO.puts("hook 1")
{:ok, results}
end)
end
prepare fn query, _ ->
Ash.Query.after_action(query, fn query, results ->
IO.puts("hook 2")
{:ok, results}
end)
end
end
```
running that action would print `hook 2` before `hook 1`.
### New Behavior
Read action hooks are now run in the order they were added
## bulk_actions_default_to_errors?
```elixir
config :ash, bulk_actions_default_to_errors?: true
```
### Old Behavior
Bulk action options defaulted to `return_errors?: false`, and `stop_on_error?: false`,
which was often a footgun for users unfamiliar to bulk actions, wondering "why did I not
get an error even though nothing was created?"
### New Behavior
Now, `return_errors?` and `stop_on_error?` default to `true`