Skip to content

Instantly share code, notes, and snippets.

@solomonhawk
Last active April 30, 2020 02:09
Show Gist options
  • Save solomonhawk/097b4a41279c50f311ca5410c7f0956b to your computer and use it in GitHub Desktop.
Save solomonhawk/097b4a41279c50f311ca5410c7f0956b to your computer and use it in GitHub Desktop.
defmodule BlogDemo.Content.Block do
use Ecto.Schema
import Ecto.Changeset
alias __MODULE__
@derive {Jason.Encoder, []}
embedded_schema do
field :content, :map
field :type, :string
field :blocks, {:array, Block}, default: []
end
@doc false
def changeset(schema, params) do
schema
|> cast(params, [:content, :type, :blocks])
end
def cast(%{ "type" => type, "content" => content, "blocks" => blocks}) do
{:ok, %{
type: type,
content: content,
blocks: Enum.map(blocks, &Block.cast/1)
}}
end
end
defmodule BlogDemo.Content.Post do
use Ecto.Schema
import Ecto.Changeset
alias BlogDemo.Content.Block
schema "posts" do
field :body, :string
field :title, :string
embeds_many :blocks, Block, on_replace: :delete
timestamps()
end
@doc false
def changeset(post, attrs) do
post
|> cast(decode_blocks(attrs), [:body, :title]) # cast_embed below fails if `attrs.blocks` is not already parsed as a struct
|> cast_embed(:blocks)
|> validate_required([:body, :title])
end
def decode_blocks(%{ "blocks" => blocks } = attrs) when is_binary(blocks) do
Map.put(attrs, "blocks", Jason.decode!(blocks))
end
def decode_blocks(attrs), do: attrs
end
# ..
def edit(conn, %{"id" => id}) do
post = id
|> Content.get_post!()
|> Content.encode_blocks() # encode blocks map to string, to insert into text input value attribute
changeset = Content.change_post(post)
render(conn, "edit.html", post: post, changeset: changeset)
end
# ..
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment