diff --git a/lib/kaffy/resource_admin.ex b/lib/kaffy/resource_admin.ex index 9ace1f05..6b4f24a0 100644 --- a/lib/kaffy/resource_admin.ex +++ b/lib/kaffy/resource_admin.ex @@ -2,6 +2,8 @@ defmodule Kaffy.ResourceAdmin do alias Kaffy.ResourceSchema alias Kaffy.Utils + @default_id_separator "." + @moduledoc """ ResourceAdmin modules should be created for every schema you want to customize/configure in Kaffy. @@ -119,7 +121,7 @@ defmodule Kaffy.ResourceAdmin do @doc """ `ordering/1` takes a schema and returns how the entries should be ordered. - If `ordering/1` is not defined, Kaffy will return `[desc: :id]`. + If `ordering/1` is not defined, Kaffy will return `[desc: primary_key]`, or the first field of the primary key, if it's a composite. Example: @@ -130,7 +132,10 @@ defmodule Kaffy.ResourceAdmin do ``` """ def ordering(resource) do - Utils.get_assigned_value_or_default(resource, :ordering, desc: :id) + schema = resource[:schema] + [order_key | _] = ResourceSchema.primary_keys(schema) + + Utils.get_assigned_value_or_default(resource, :ordering, desc: order_key) end @doc """ @@ -293,6 +298,52 @@ defmodule Kaffy.ResourceAdmin do Utils.get_assigned_value_or_default(resource, :plural_name, default) end + @doc """ + `serialize_id/2` takes a schema and record and must return a string to be used in the URL and form values. + + If `serialize_id/2` is not defined, Kaffy will concatenate multiple primary keys with `"."` as a separator. + + Example: + + ```elixir + def serialize_id(_schema, record) do + Enum.join([record.post_id, record.tag_id], ".") + end + ``` + """ + def serialize_id(resource, entry) do + schema = resource[:schema] + default = schema + |> ResourceSchema.primary_keys() + |> Enum.map_join(@default_id_separator, &Map.get(entry, &1)) + + Utils.get_assigned_value_or_default(resource, :serialize_id, default, [entry]) + end + + @doc """ + `deserialize_id/2` takes a schema and serialized id and must return a complete + keyword list in the form of [{:primary_key, value}, ...]. + + If `deserialize_id/2` is not defined, Kaffy will split multiple primary keys with `"."` as a separator. + + Example: + + ```elixir + def serialize_id(_schema, serialized_id) do + Enum.zip([:post_id, :tag_id], String.split(serialized_id, ".")) + end + ``` + """ + def deserialize_id(resource, id) do + schema = resource[:schema] + id_list = String.split(id, @default_id_separator) + default = schema + |> ResourceSchema.primary_keys() + |> Enum.zip(id_list) + + Utils.get_assigned_value_or_default(resource, :deserialize_id, default, [id]) + end + def resource_actions(resource, conn) do Utils.get_assigned_value_or_default(resource, :resource_actions, nil, [conn], false) end diff --git a/lib/kaffy/resource_form.ex b/lib/kaffy/resource_form.ex index 21d65c52..c07285c4 100644 --- a/lib/kaffy/resource_form.ex +++ b/lib/kaffy/resource_form.ex @@ -49,8 +49,14 @@ defmodule Kaffy.ResourceForm do opts end + # Check if any primary key fields are nil + is_create_event = changeset.data.__struct__ + |> Kaffy.ResourceSchema.primary_keys() + |> Enum.map(&Map.get(changeset.data, &1)) + |> Enum.any?(&is_nil/1) + permission = - case is_nil(changeset.data.id) do + case is_create_event do true -> Map.get(options, :create, :editable) false -> Map.get(options, :update, :editable) end @@ -102,13 +108,13 @@ defmodule Kaffy.ResourceForm do end) :id -> - case Kaffy.ResourceSchema.primary_key(schema) == [field] do + case field in Kaffy.ResourceSchema.primary_keys(schema) do true -> text_input(form, field, opts) false -> text_or_assoc(conn, schema, form, field, opts) end :binary_id -> - case Kaffy.ResourceSchema.primary_key(schema) == [field] do + case field in Kaffy.ResourceSchema.primary_keys(schema) do true -> text_input(form, field, opts) false -> text_or_assoc(conn, schema, form, field, opts) end diff --git a/lib/kaffy/resource_query.ex b/lib/kaffy/resource_query.ex index 3dfc05b1..80dda378 100644 --- a/lib/kaffy/resource_query.ex +++ b/lib/kaffy/resource_query.ex @@ -46,7 +46,8 @@ defmodule Kaffy.ResourceQuery do def fetch_resource(conn, resource, id) do schema = resource[:schema] - query = from(s in schema, where: s.id == ^id) + id_filter = Kaffy.ResourceAdmin.deserialize_id(resource, id) + query = from(s in schema, where: ^id_filter) custom_query = Kaffy.ResourceAdmin.custom_show_query(conn, resource, query) Kaffy.Utils.repo().one(custom_query) end diff --git a/lib/kaffy/resource_schema.ex b/lib/kaffy/resource_schema.ex index f7d5335c..4dc15069 100644 --- a/lib/kaffy/resource_schema.ex +++ b/lib/kaffy/resource_schema.ex @@ -1,7 +1,7 @@ defmodule Kaffy.ResourceSchema do @moduledoc false - def primary_key(schema) do + def primary_keys(schema) do schema.__schema__(:primary_key) end @@ -24,7 +24,10 @@ defmodule Kaffy.ResourceSchema do end def form_fields(schema) do - to_be_removed = fields_to_be_removed(schema) ++ [:id, :inserted_at, :updated_at] + to_be_removed = + fields_to_be_removed(schema) ++ + primary_keys(schema) ++ + [:inserted_at, :updated_at] Keyword.drop(fields(schema), to_be_removed) end @@ -33,7 +36,9 @@ defmodule Kaffy.ResourceSchema do fields_to_be_removed(schema) ++ get_has_many_associations(schema) ++ get_has_one_assocations(schema) ++ - get_many_to_many_associations(schema) ++ [:id, :inserted_at, :updated_at] + get_many_to_many_associations(schema) ++ + primary_keys(schema) ++ + [:inserted_at, :updated_at] Keyword.drop(fields(schema), to_be_removed) end diff --git a/lib/kaffy_web/controllers/resource_controller.ex b/lib/kaffy_web/controllers/resource_controller.ex index bc1f32ae..871b4a4a 100644 --- a/lib/kaffy_web/controllers/resource_controller.ex +++ b/lib/kaffy_web/controllers/resource_controller.ex @@ -383,6 +383,8 @@ defmodule KaffyWeb.ResourceController do end defp redirect_to_resource(conn, context, resource, entry) do + id = Kaffy.ResourceAdmin.serialize_id(resource, entry) + redirect(conn, to: Kaffy.Utils.router().kaffy_resource_path( @@ -390,7 +392,7 @@ defmodule KaffyWeb.ResourceController do :show, context, resource, - entry.id + id ) ) end diff --git a/lib/kaffy_web/templates/resource/_table.html.eex b/lib/kaffy_web/templates/resource/_table.html.eex index 3ece2efa..e81de33d 100644 --- a/lib/kaffy_web/templates/resource/_table.html.eex +++ b/lib/kaffy_web/templates/resource/_table.html.eex @@ -4,17 +4,17 @@
- <%= for entry <- @entries do %> + <%= for {entry, index} <- Enum.with_index(@entries) do %>