venomnert
Ecto.update is not updating jsonb
The problem
I have a :map field that I am able to update on create. On update, the changeset returns a successful update;however, the database jsonb is not reflecting the changes. I’m unable to determine what the issue is.
Schema:
schema "promo_jobs" do
field(:content, :map, default: %{})
field(:draft, :boolean, default: true)
field(:end_date, :utc_datetime)
field(:name, :string)
field(:rolled_out, :boolean, default: false)
field(:start_date, :utc_datetime)
field(:take_down, :boolean, default: false)
has_one(:landing_page_url, LandingPageUrl, on_replace: :nilify, on_delete: :nilify_all)
belongs_to(:region, Region)
end
def changeset(promo_job, attrs) do
promo_job
|> add_content(attrs)
|> cast(attrs, [:name, :rolled_out, :take_down, :start_date, :end_date, :content, :draft])
|> validate_required([
:name,
:rolled_out,
:take_down,
:start_date,
:end_date,
:content,
:draft
])
end
defp add_content(promo_job, attrs) do
promo_job
|> Map.put(:content,
Morphix.atomorphiform!(promo_job.content)
|> Content.new()
|> Content.update_input_value(attrs))
end
Controller:
def show(conn, %{"id" => id}) do
promo_job = Promos.get_promo_job!(id) |> IO.inspect(label: "SHOW")
render(conn, "show.html", promo_job: promo_job)
end
def update(conn, %{"id" => id, "promo_job" => promo_job_params}) do
promo_job = Promos.get_promo_job!(id)
case Promos.update_promo_job(promo_job, promo_job_params) do
{:ok, promo_job} ->
IO.inspect(promo_job, label: "UODATED")
conn
|> put_flash(:info, "Promo job updated successfully.")
|> redirect(to: Routes.promo_job_path(conn, :show, promo_job))
{:error, %Ecto.Changeset{} = changeset} ->
render(conn, "edit.html", promo_job: promo_job, changeset: changeset)
end
end
Context:
def create_promo_job(attrs \\ %{}) do
promo_job = %PromoJob{} |> PromoJob.changeset(attrs)
promo_job
|> Repo.insert()
end
def update_promo_job(%PromoJob{} = promo_job, attrs) do
promo_job
|> PromoJob.changeset(attrs)
|> Repo.update()
end
Inspect Logs:
UODATED: %PromoRollout.Promos.PromoJob{
__meta__: #Ecto.Schema.Metadata<:loaded, "promo_jobs">,
content: %{
body_promo: %{
fields: [
%{
content: "abab",
field_type: "text_input",
name: "bg_mobile",
placeholder: "Image url"
},
%{
content: "2312312",
field_type: "text_input",
name: "bg_desktop",
placeholder: "Image url"
}
],
full_html: "",
status: false
},
promo_bar: %{
fields: [
%{
content: "zcxzc",
field_type: "text_input",
name: "image_url",
placeholder: "Image url"
}
],
full_html: "",
status: false
}
},
draft: false,
end_date: ~U[2020-01-01 00:00:00Z],
id: 25,
inserted_at: ~N[2020-01-30 23:06:54],
landing_page_url: %PromoRollout.Promos.LandingPageUrl{
__meta__: #Ecto.Schema.Metadata<:loaded, "landing_page_urls">,
draft: true,
end_date: ~U[2020-01-01 00:00:00Z],
id: 1,
inserted_at: ~N[2020-01-25 12:20:57],
promo_job: #Ecto.Association.NotLoaded<association :promo_job is not loaded>,
promo_job_id: 25,
redirected: false,
updated_at: ~N[2020-01-30 23:30:03],
url: "/lp/easter"
},
name: "testing 123",
region: nil,
region_id: nil,
rolled_out: false,
start_date: ~U[2020-01-01 00:00:00Z],
take_down: false,
updated_at: ~N[2020-01-30 23:30:03]
}
SHOW: %PromoRollout.Promos.PromoJob{
__meta__: #Ecto.Schema.Metadata<:loaded, "promo_jobs">,
content: %{
"body_promo" => %{
"fields" => [
%{
"content" => "21312321321",
"field_type" => "text_input",
"name" => "bg_mobile",
"placeholder" => "Image url"
},
%{
"content" => "dsfasfasfsfss",
"field_type" => "text_input",
"name" => "bg_desktop",
"placeholder" => "Image url"
}
],
"full_html" => "",
"status" => false
},
"promo_bar" => %{
"fields" => [
%{
"content" => "xzzzxZxxzx",
"field_type" => "text_input",
"name" => "image_url",
"placeholder" => "Image url"
}
],
"full_html" => "",
"status" => false
}
},
draft: false,
end_date: ~U[2020-01-01 00:00:00Z],
id: 25,
inserted_at: ~N[2020-01-30 23:06:54],
landing_page_url: %PromoRollout.Promos.LandingPageUrl{
__meta__: #Ecto.Schema.Metadata<:loaded, "landing_page_urls">,
draft: true,
end_date: ~U[2020-01-01 00:00:00Z],
id: 1,
inserted_at: ~N[2020-01-25 12:20:57],
promo_job: #Ecto.Association.NotLoaded<association :promo_job is not loaded>,
promo_job_id: 25,
redirected: false,
updated_at: ~N[2020-01-30 23:30:03],
url: "/lp/easter"
},
name: "testing 123",
region: #Ecto.Association.NotLoaded<association :region is not loaded>,
region_id: nil,
rolled_out: false,
start_date: ~U[2020-01-01 00:00:00Z],
take_down: false,
updated_at: ~N[2020-01-30 23:30:03]
}
You will notices that the update log is correct, it reflects all the changes I’ve made. Once we are directed to the show route, the data that’s retrieved from the db has some inconsistency. The name gets updated correctly, but the content the :map field doesn’t get updated, it shows the old value. Which is the main problem I am having.
Marked As Solved
venomnert
I was able to resolve the issue, thanks to Ecto’s documentation
A changeset is required as it is the only mechanism for tracking dirty changes. Only the fields present in the
changespart of the changeset are sent to the database. Any other, in-memory changes done to the schema are ignored.
Looks like I wasn’t setting the change field for the changeset. So here is the update PromoJob.changeset
defp add_content(promo_job, attrs) do
promo_job
|>put_change(:content,
Morphix.atomorphiform!(promo_job.data.content)
|> Content.new()
|> Content.update_input_value(attrs))
end
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









