mirror of
https://github.com/ash-project/ash_blog.git
synced 2024-09-19 12:53:45 +12:00
improvement: wrap up initial ash_blog behavior
This commit is contained in:
parent
2053a56c20
commit
56ca4116c6
9 changed files with 189 additions and 19 deletions
|
@ -2,4 +2,67 @@ defmodule AshBlog do
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
Documentation for `AshBlog`.
|
Documentation for `AshBlog`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import XmlBuilder
|
||||||
|
|
||||||
|
def rss_feed(blog_posts, opts \\ []) do
|
||||||
|
blog_posts = Enum.filter(blog_posts, &(&1.state == :published))
|
||||||
|
|
||||||
|
element(
|
||||||
|
:feed,
|
||||||
|
%{xmlns: "http://www.w3.org/2005/Atom"},
|
||||||
|
[
|
||||||
|
element(:title, "Ash Framework Blog"),
|
||||||
|
element(:link, "https://ash-hq.org/blog"),
|
||||||
|
element(
|
||||||
|
:description,
|
||||||
|
"News and information about Ash Framework, a declarative, resource oriented Elixir application development framework."
|
||||||
|
)
|
||||||
|
] ++
|
||||||
|
Enum.map(blog_posts, fn %resource{} = blog_post ->
|
||||||
|
data = [
|
||||||
|
title: Map.get(blog_post, AshBlog.DataLayer.Info.title_attribute(resource))
|
||||||
|
]
|
||||||
|
|
||||||
|
data =
|
||||||
|
if opts[:linker] do
|
||||||
|
Keyword.put(data, :link, opts[:linker].(blog_post))
|
||||||
|
else
|
||||||
|
data
|
||||||
|
end
|
||||||
|
|
||||||
|
inners =
|
||||||
|
if opts[:html_body] do
|
||||||
|
[element(:content, %{type: "html"}, {:cdata, opts[:html_body].(blog_post)})]
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
|
||||||
|
inners =
|
||||||
|
if opts[:summary] do
|
||||||
|
[element(:summary, %{type: "html"}, {:cdata, opts[:summary].(blog_post)}) | inners]
|
||||||
|
else
|
||||||
|
inners
|
||||||
|
end
|
||||||
|
|
||||||
|
inners =
|
||||||
|
if opts[:author] do
|
||||||
|
[element(:author, name: opts[:author].(blog_post)) | inners]
|
||||||
|
else
|
||||||
|
inners
|
||||||
|
end
|
||||||
|
|
||||||
|
data =
|
||||||
|
Keyword.put(
|
||||||
|
data,
|
||||||
|
:id,
|
||||||
|
Ash.Resource.Info.primary_key(resource)
|
||||||
|
|> Enum.map_join("-", &to_string(Map.get(blog_post, &1)))
|
||||||
|
)
|
||||||
|
|
||||||
|
element(:item, data, inners)
|
||||||
|
end)
|
||||||
|
)
|
||||||
|
|> XmlBuilder.generate()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
45
lib/data_layer/changes/set_and_track_slug.ex
Normal file
45
lib/data_layer/changes/set_and_track_slug.ex
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
defmodule AshBlog.DataLayer.Changes.SetAndTrackSlug do
|
||||||
|
use Ash.Resource.Change
|
||||||
|
|
||||||
|
def change(changeset, _, _) do
|
||||||
|
slug_attribute = AshBlog.DataLayer.Info.slug_attribute(changeset.resource)
|
||||||
|
|
||||||
|
if changeset.action_type == :create do
|
||||||
|
if Ash.Changeset.get_attribute(changeset, :slug) do
|
||||||
|
changeset
|
||||||
|
else
|
||||||
|
set_default_slug(changeset, slug_attribute)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if Ash.Changeset.changing_attribute?(changeset, slug_attribute) && changeset.data.slug do
|
||||||
|
past_slugs = Ash.Changeset.get_attribute(changeset, :past_slugs) || []
|
||||||
|
|
||||||
|
Ash.Changeset.force_change_attribute(changeset, :past_slugs, [
|
||||||
|
changeset.data.slug | past_slugs
|
||||||
|
])
|
||||||
|
else
|
||||||
|
changeset
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp set_default_slug(changeset, slug_attribute) do
|
||||||
|
title_attribute = AshBlog.DataLayer.Info.title_attribute(changeset.resource)
|
||||||
|
|
||||||
|
Ash.Changeset.force_change_attribute(
|
||||||
|
changeset,
|
||||||
|
slug_attribute,
|
||||||
|
to_slug(Ash.Changeset.get_attribute(changeset, title_attribute))
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp to_slug(nil), do: nil
|
||||||
|
|
||||||
|
defp to_slug(title) do
|
||||||
|
title
|
||||||
|
|> String.replace(~r/\s+/, " ")
|
||||||
|
|> String.replace(" ", "-")
|
||||||
|
|> String.replace(~r/[^A-Za-z0-9-]/, "")
|
||||||
|
|> String.downcase()
|
||||||
|
end
|
||||||
|
end
|
|
@ -41,6 +41,12 @@ defmodule AshBlog.DataLayer do
|
||||||
doc:
|
doc:
|
||||||
"The attribute name to use for the body of the post. Wil be created if it doesn't exist."
|
"The attribute name to use for the body of the post. Wil be created if it doesn't exist."
|
||||||
],
|
],
|
||||||
|
slug_attribute: [
|
||||||
|
type: :atom,
|
||||||
|
default: :slug,
|
||||||
|
doc:
|
||||||
|
"The attribute name to use for the slug. All past slugs will be stored and used when looking up by slug."
|
||||||
|
],
|
||||||
folder: [
|
folder: [
|
||||||
type: :string,
|
type: :string,
|
||||||
default: "blog/published",
|
default: "blog/published",
|
||||||
|
@ -468,7 +474,9 @@ defmodule AshBlog.DataLayer do
|
||||||
|> Ash.Resource.Info.attributes()
|
|> Ash.Resource.Info.attributes()
|
||||||
|> Enum.reject(&(&1.name == body_attribute))
|
|> Enum.reject(&(&1.name == body_attribute))
|
||||||
|> Enum.reduce_while({:ok, []}, fn attr, {:ok, acc} ->
|
|> Enum.reduce_while({:ok, []}, fn attr, {:ok, acc} ->
|
||||||
if Ash.Type.storage_type(attr.type) in [
|
storage_type = Ash.Type.storage_type(unwrap_array(attr.type))
|
||||||
|
|
||||||
|
if storage_type in [
|
||||||
:string,
|
:string,
|
||||||
:integer,
|
:integer,
|
||||||
:uuid,
|
:uuid,
|
||||||
|
@ -483,7 +491,9 @@ defmodule AshBlog.DataLayer do
|
||||||
{:halt, {:error, error}}
|
{:halt, {:error, error}}
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
{:halt, {:error, "#{inspect(attr.type)} is not yet supported by `AshBlog.DataLayer`"}}
|
{:halt,
|
||||||
|
{:error,
|
||||||
|
"#{inspect(attr.type)} with storage type #{inspect(storage_type)} is not yet supported by `AshBlog.DataLayer`"}}
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|> case do
|
|> case do
|
||||||
|
@ -492,16 +502,7 @@ defmodule AshBlog.DataLayer do
|
||||||
attrs
|
attrs
|
||||||
|> Enum.reverse()
|
|> Enum.reverse()
|
||||||
|> Enum.map_join("\n", fn {name, value} ->
|
|> Enum.map_join("\n", fn {name, value} ->
|
||||||
case value do
|
"#{name}: #{encode(value)}"
|
||||||
value when is_binary(value) ->
|
|
||||||
"#{name}: '#{escape_string(value)}'"
|
|
||||||
|
|
||||||
%DateTime{} = value ->
|
|
||||||
"#{name}: '#{escape_string(value)}'"
|
|
||||||
|
|
||||||
other ->
|
|
||||||
"#{name}: #{other}"
|
|
||||||
end
|
|
||||||
end)}
|
end)}
|
||||||
|
|
||||||
{:error, error} ->
|
{:error, error} ->
|
||||||
|
@ -509,6 +510,34 @@ defmodule AshBlog.DataLayer do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def encode(value, indentation \\ 2) do
|
||||||
|
case value do
|
||||||
|
value when is_binary(value) ->
|
||||||
|
"'#{escape_string(value)}'"
|
||||||
|
|
||||||
|
%DateTime{} = value ->
|
||||||
|
"'#{escape_string(value)}'"
|
||||||
|
|
||||||
|
[] ->
|
||||||
|
"[]"
|
||||||
|
|
||||||
|
list when is_list(value) ->
|
||||||
|
"\n#{listify(list, indentation)}"
|
||||||
|
|
||||||
|
other ->
|
||||||
|
to_string(other)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def listify(value, indentation \\ 2) do
|
||||||
|
Enum.map_join(value, "\n", fn value ->
|
||||||
|
"#{String.duplicate(" ", indentation)}- #{encode(value, indentation + 2)}"
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp unwrap_array({:array, value}), do: unwrap_array(value)
|
||||||
|
defp unwrap_array(value), do: value
|
||||||
|
|
||||||
defp escape_string(value) do
|
defp escape_string(value) do
|
||||||
value
|
value
|
||||||
|> to_string()
|
|> to_string()
|
||||||
|
@ -647,7 +676,7 @@ defmodule AshBlog.DataLayer do
|
||||||
|
|
||||||
all_in_transaction(tx_identifiers, fn ->
|
all_in_transaction(tx_identifiers, fn ->
|
||||||
try do
|
try do
|
||||||
fun.()
|
{:ok, fun.()}
|
||||||
catch
|
catch
|
||||||
{{:blog_rollback, rolled_back_tx_identifiers}, value} = thrown ->
|
{{:blog_rollback, rolled_back_tx_identifiers}, value} = thrown ->
|
||||||
if Enum.any?(tx_identifiers, &(&1 in rolled_back_tx_identifiers)) do
|
if Enum.any?(tx_identifiers, &(&1 in rolled_back_tx_identifiers)) do
|
||||||
|
@ -660,7 +689,7 @@ defmodule AshBlog.DataLayer do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp all_in_transaction([], fun) do
|
defp all_in_transaction([], fun) do
|
||||||
{:ok, fun.()}
|
fun.()
|
||||||
end
|
end
|
||||||
|
|
||||||
defp all_in_transaction([tx_identifier | rest], fun) do
|
defp all_in_transaction([tx_identifier | rest], fun) do
|
||||||
|
|
|
@ -29,6 +29,10 @@ defmodule AshBlog.DataLayer.Info do
|
||||||
Extension.get_opt(resource, [:blog], :body_attribute, :body)
|
Extension.get_opt(resource, [:blog], :body_attribute, :body)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def slug_attribute(resource) do
|
||||||
|
Extension.get_opt(resource, [:blog], :slug_attribute, :slug)
|
||||||
|
end
|
||||||
|
|
||||||
def title_attribute(resource) do
|
def title_attribute(resource) do
|
||||||
Extension.get_opt(resource, [:blog], :title_attribute, :title)
|
Extension.get_opt(resource, [:blog], :title_attribute, :title)
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,21 +9,39 @@ defmodule AshBlog.DataLayer.Transformers.AddStructure do
|
||||||
|> Ash.Resource.Builder.add_new_attribute(Info.title_attribute(dsl_state), :string,
|
|> Ash.Resource.Builder.add_new_attribute(Info.title_attribute(dsl_state), :string,
|
||||||
allow_nil?: false
|
allow_nil?: false
|
||||||
)
|
)
|
||||||
|
|> Ash.Resource.Builder.add_new_attribute(Info.slug_attribute(dsl_state), :string,
|
||||||
|
allow_nil?: false
|
||||||
|
)
|
||||||
|
|> Ash.Resource.Builder.add_new_attribute(:past_slugs, {:array, :string},
|
||||||
|
allow_nil?: false,
|
||||||
|
default: [],
|
||||||
|
writable?: false
|
||||||
|
)
|
||||||
|> Ash.Resource.Builder.add_new_attribute(Info.body_attribute(dsl_state), :string,
|
|> Ash.Resource.Builder.add_new_attribute(Info.body_attribute(dsl_state), :string,
|
||||||
allow_nil?: false
|
allow_nil?: false
|
||||||
)
|
)
|
||||||
|> Ash.Resource.Builder.add_new_attribute(:state, :atom,
|
|> Ash.Resource.Builder.add_new_attribute(:state, :atom,
|
||||||
constraints: [one_of: [:staged, :published, :archived]],
|
constraints: [one_of: [:staged, :published, :archived]],
|
||||||
default: :staged
|
default: :staged,
|
||||||
|
writable?: false
|
||||||
|
)
|
||||||
|
|> Ash.Resource.Builder.add_new_attribute(:published_at, :utc_datetime_usec, writable?: false)
|
||||||
|
|> Ash.Resource.Builder.add_change(AshBlog.DataLayer.Changes.SetAndTrackSlug,
|
||||||
|
on: [:create, :update]
|
||||||
)
|
)
|
||||||
|> Ash.Resource.Builder.add_new_action(:update, :publish,
|
|> Ash.Resource.Builder.add_new_action(:update, :publish,
|
||||||
|
accept: [],
|
||||||
changes: [
|
changes: [
|
||||||
Ash.Resource.Builder.build_action_change(
|
Ash.Resource.Builder.build_action_change(
|
||||||
Ash.Resource.Change.Builtins.set_attribute(:state, :published)
|
Ash.Resource.Change.Builtins.set_attribute(:state, :published)
|
||||||
|
),
|
||||||
|
Ash.Resource.Builder.build_action_change(
|
||||||
|
Ash.Resource.Change.Builtins.set_attribute(:published_at, &DateTime.utc_now/0)
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|> Ash.Resource.Builder.add_new_action(:update, :stage,
|
|> Ash.Resource.Builder.add_new_action(:update, :stage,
|
||||||
|
accept: [],
|
||||||
changes: [
|
changes: [
|
||||||
Ash.Resource.Builder.build_action_change(
|
Ash.Resource.Builder.build_action_change(
|
||||||
Ash.Resource.Change.Builtins.set_attribute(:state, :staged)
|
Ash.Resource.Change.Builtins.set_attribute(:state, :staged)
|
||||||
|
@ -31,6 +49,7 @@ defmodule AshBlog.DataLayer.Transformers.AddStructure do
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|> Ash.Resource.Builder.add_new_action(:update, :archive,
|
|> Ash.Resource.Builder.add_new_action(:update, :archive,
|
||||||
|
accept: [],
|
||||||
changes: [
|
changes: [
|
||||||
Ash.Resource.Builder.build_action_change(
|
Ash.Resource.Builder.build_action_change(
|
||||||
Ash.Resource.Change.Builtins.set_attribute(:state, :archived)
|
Ash.Resource.Change.Builtins.set_attribute(:state, :archived)
|
||||||
|
|
5
mix.exs
5
mix.exs
|
@ -109,9 +109,10 @@ defmodule AshBlog.MixProject do
|
||||||
# Run "mix help deps" to learn about dependencies.
|
# Run "mix help deps" to learn about dependencies.
|
||||||
defp deps do
|
defp deps do
|
||||||
[
|
[
|
||||||
{:ash, github: "ash-project/ash"},
|
# {:ash, github: "ash-project/ash"},
|
||||||
# {:ash, path: "../ash"},
|
{:ash, path: "../ash"},
|
||||||
{:yaml_elixir, "~> 2.9"},
|
{:yaml_elixir, "~> 2.9"},
|
||||||
|
{:xml_builder, "~> 2.2"},
|
||||||
|
|
||||||
# dev/test dependencies
|
# dev/test dependencies
|
||||||
{:elixir_sense,
|
{:elixir_sense,
|
||||||
|
|
4
mix.lock
4
mix.lock
|
@ -33,14 +33,16 @@
|
||||||
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
|
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
|
||||||
"picosat_elixir": {:hex, :picosat_elixir, "0.2.2", "1cacfdb4fb0c3ead5e5e9b1e98ac822a777f07eab35e29c3f8fc7086de2bfb36", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "9d0cc569552cca417abea8270a54b71153a63be4b951ff249e94642f1c0f35d1"},
|
"picosat_elixir": {:hex, :picosat_elixir, "0.2.2", "1cacfdb4fb0c3ead5e5e9b1e98ac822a777f07eab35e29c3f8fc7086de2bfb36", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "9d0cc569552cca417abea8270a54b71153a63be4b951ff249e94642f1c0f35d1"},
|
||||||
"providers": {:hex, :providers, "1.8.1", "70b4197869514344a8a60e2b2a4ef41ca03def43cfb1712ecf076a0f3c62f083", [:rebar3], [{:getopt, "1.0.1", [hex: :getopt, repo: "hexpm", optional: false]}], "hexpm", "e45745ade9c476a9a469ea0840e418ab19360dc44f01a233304e118a44486ba0"},
|
"providers": {:hex, :providers, "1.8.1", "70b4197869514344a8a60e2b2a4ef41ca03def43cfb1712ecf076a0f3c62f083", [:rebar3], [{:getopt, "1.0.1", [hex: :getopt, repo: "hexpm", optional: false]}], "hexpm", "e45745ade9c476a9a469ea0840e418ab19360dc44f01a233304e118a44486ba0"},
|
||||||
|
"rss": {:hex, :rss, "0.2.1", "034f2fe5250a490862e692eb34a31bb5c142913c2fe0fb093e1fd982f010e15d", [:mix], [], "hexpm", "1af49c787fc789740a0fa7e0e197a7cb779a63c4eb703f013fea400126eac1f2"},
|
||||||
"sobelow": {:hex, :sobelow, "0.11.1", "23438964486f8112b41e743bbfd402da3e5b296fdc9eacab29914b79c48916dd", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "9897363a7eff96f4809304a90aad819e2ad5e5d24db547af502885146746a53c"},
|
"sobelow": {:hex, :sobelow, "0.11.1", "23438964486f8112b41e743bbfd402da3e5b296fdc9eacab29914b79c48916dd", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "9897363a7eff96f4809304a90aad819e2ad5e5d24db547af502885146746a53c"},
|
||||||
"sourceror": {:hex, :sourceror, "0.11.2", "549ce48be666421ac60cfb7f59c8752e0d393baa0b14d06271d3f6a8c1b027ab", [:mix], [], "hexpm", "9ab659118896a36be6eec68ff7b0674cba372fc8e210b1e9dc8cf2b55bb70dfb"},
|
"sourceror": {:hex, :sourceror, "0.11.2", "549ce48be666421ac60cfb7f59c8752e0d393baa0b14d06271d3f6a8c1b027ab", [:mix], [], "hexpm", "9ab659118896a36be6eec68ff7b0674cba372fc8e210b1e9dc8cf2b55bb70dfb"},
|
||||||
"spark": {:hex, :spark, "0.2.3", "3678177ca1f1f4c7919da90b49f5e378c39e1bdf2f59ad8909c0c3591fe8dbb6", [:mix], [{:nimble_options, "~> 0.4.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:sourceror, "~> 0.1", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "933dadc7fcce93198104e7d88243772bbde9e54b001929a4c04bc733812e8e3b"},
|
"spark": {:hex, :spark, "0.2.6", "84dbfe7153dc51f988a2b43f28031be87dee724d2ac535069d05807cfacde7c4", [:mix], [{:nimble_options, "~> 0.4.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:sourceror, "~> 0.1", [hex: :sourceror, repo: "hexpm", optional: false]}], "hexpm", "f0fba891abc70d4e7431b3ed6283ee46ccd6e8045e0bfdce13bc06e8904bbd25"},
|
||||||
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
|
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
|
||||||
"stream_data": {:hex, :stream_data, "0.5.0", "b27641e58941685c75b353577dc602c9d2c12292dd84babf506c2033cd97893e", [:mix], [], "hexpm", "012bd2eec069ada4db3411f9115ccafa38540a3c78c4c0349f151fc761b9e271"},
|
"stream_data": {:hex, :stream_data, "0.5.0", "b27641e58941685c75b353577dc602c9d2c12292dd84babf506c2033cd97893e", [:mix], [], "hexpm", "012bd2eec069ada4db3411f9115ccafa38540a3c78c4c0349f151fc761b9e271"},
|
||||||
"telemetry": {:hex, :telemetry, "1.1.0", "a589817034a27eab11144ad24d5c0f9fab1f58173274b1e9bae7074af9cbee51", [:rebar3], [], "hexpm", "b727b2a1f75614774cff2d7565b64d0dfa5bd52ba517f16543e6fc7efcc0df48"},
|
"telemetry": {:hex, :telemetry, "1.1.0", "a589817034a27eab11144ad24d5c0f9fab1f58173274b1e9bae7074af9cbee51", [:rebar3], [], "hexpm", "b727b2a1f75614774cff2d7565b64d0dfa5bd52ba517f16543e6fc7efcc0df48"},
|
||||||
"typable": {:hex, :typable, "0.3.0", "0431e121d124cd26f312123e313d2689b9a5322b15add65d424c07779eaa3ca1", [:mix], [], "hexpm", "880a0797752da1a4c508ac48f94711e04c86156f498065a83d160eef945858f8"},
|
"typable": {:hex, :typable, "0.3.0", "0431e121d124cd26f312123e313d2689b9a5322b15add65d424c07779eaa3ca1", [:mix], [], "hexpm", "880a0797752da1a4c508ac48f94711e04c86156f498065a83d160eef945858f8"},
|
||||||
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
|
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
|
||||||
|
"xml_builder": {:hex, :xml_builder, "2.2.0", "cc5f1eeefcfcde6e90a9b77fb6c490a20bc1b856a7010ce6396f6da9719cbbab", [:mix], [], "hexpm", "9d66d52fb917565d358166a4314078d39ef04d552904de96f8e73f68f64a62c9"},
|
||||||
"yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"},
|
"yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"},
|
||||||
"yaml_elixir": {:hex, :yaml_elixir, "2.9.0", "9a256da867b37b8d2c1ffd5d9de373a4fda77a32a45b452f1708508ba7bbcb53", [:mix], [{:yamerl, "~> 0.10", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "0cb0e7d4c56f5e99a6253ed1a670ed0e39c13fc45a6da054033928607ac08dfc"},
|
"yaml_elixir": {:hex, :yaml_elixir, "2.9.0", "9a256da867b37b8d2c1ffd5d9de373a4fda77a32a45b452f1708508ba7bbcb53", [:mix], [{:yamerl, "~> 0.10", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "0cb0e7d4c56f5e99a6253ed1a670ed0e39c13fc45a6da054033928607ac08dfc"},
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,13 @@ defmodule AshBlogTest do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "slug" do
|
||||||
|
test "a slug is auto generated" do
|
||||||
|
Post.create!("first", "the body") |> IO.inspect()
|
||||||
|
Post.read!()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "updating blog posts" do
|
describe "updating blog posts" do
|
||||||
test "blog posts can be published" do
|
test "blog posts can be published" do
|
||||||
post = Post.create!("first\"", "the body")
|
post = Post.create!("first\"", "the body")
|
||||||
|
|
|
@ -5,7 +5,7 @@ defmodule AshBlog.Test.Post do
|
||||||
data_layer: AshBlog.DataLayer
|
data_layer: AshBlog.DataLayer
|
||||||
|
|
||||||
actions do
|
actions do
|
||||||
defaults [:create, :read]
|
defaults [:create, :read, :update]
|
||||||
end
|
end
|
||||||
|
|
||||||
attributes do
|
attributes do
|
||||||
|
|
Loading…
Reference in a new issue