krut

krut

Discard invalid embed entries during casting

I am wondering if there is an idiomatic way to discard invalid embed entries during casting, i.e. when Ecto.Changeset.cast_embed/3 is called, as opposed to marking them as invalid, which will in turn make the parent changeset invalid.

As an example - I have a number of nested embedded schemas that are used to cast incoming webhook data, e.g. a Post that embeds_many :comments. These comments can either be active or inactive (e.g. a deleted comment).

The application only cares about comments that are active, which I can identify by using Ecto.Changeset.validate_inclusion/4 on the comment’s :status. However, this will cause the inactive comments to be marked as invalid, which will then make the parent post invalid.

I was thinking it would be nice if I could discard the invalid embeds (for this particular field), and send the post (with only active comments) through, as it would simplify the business logic in multiple areas.

Does this functionality exist in Ecto? Or would this be a kind of anti-pattern / bad approach? Would love to hear any thoughts.

Marked As Solved

cenotaph

cenotaph

Let’s approach SOLID, FP and philosophically

Changeset as correctly named, set of changes. Should only carry and work on the changes. Its scope should start and end with the changes [validation, casting]. It should not mutate the changes.

If the consumer pushes n changes, I have two options, filter before or after I provide it as a change.

then depending on my use case I would validate changes accordingly.

  • I could ask my consumer to send only active records since I am the owner of the contract to decrease payloads.
  • Depending on my payload, I would filter() |> validate() as early as possible before operate()
  • I would have a very specific use case changeset to satisfy the needs.
payload
|> filter_out_inactive_comments(..)
|> Post.bulk_update_changeset(..)
|> update_post(..)

bulk_update_changeset(...) do
  ...
  |> validate_inclusion(...)
  |> validate_length(..)
  |> validate_assoc(..)
  ...
end

Also Liked

oliveiragahenrique

oliveiragahenrique

I think that changesets are not meant to be used like that.

You may be better served by calling the classic Enum.filter/2 before Ecto.Changeset.cast_embed/3, because all you want is just that, filter specific elements from a set of elements! :smile:

krut

krut

Thank you for such a detailed explanation and example! :pray: That all makes sense and is very helpful.

I had been filtering in the operate() stage, which was complicating things and causing unnecessary duplication.

I think I will want to filter “before” then…for some reason I wasn’t considering that, and thinking that the casting should come first. Thanks again!

krut

krut

Thank you! I suspected that might be the case :sweat_smile:I think you’re spot on with filtering before.

Where Next?

Popular in Questions Top

Werner
Hi, I’m using Ubuntu 18.04 and after updating to OTP-24.0 yesterday i have this warning when I run “mix local.hex”: 14:57:30.512 [warn] ...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
LegitStack
I’m trying to make a websocket server in Phoenix or raw Elixir. I heard about gun, I think I could use cowboy, but since I’m not that sma...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
kostonstyle
Hi all I want to have a unix time, from the current time plus 1 hour. DateTime.now + 1 hour How to get it in elixir? Thanks
New
beno
I will often find my self writing things similar to: case some_value do nil -> something() "" -> something() _ -> someth...
New
sabri
Can someone explain the settings of pool_size of Ecto in config file? and what is the recommend size? Thanks
New
Mooodi
Given a string, how can I get access to its character by index? Enum.at("my_string", 2) doesn't work. Or rather, not char, but a substr...
New

Other popular topics Top

pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New

We're in Beta

About us Mission Statement