endymion

endymion

Changes not properly applied with Ecto.Changeset.apply_changes/1

I am wondering why when I ran Ecto.Changeset.apply_changes(changeset) the prepared changes function on that changeset did not run. I have a changeset that I am building from a Phoenix form; after validation occurs and user submits the form, I want to apply those params to my struct with a prepared change to increment a value of one of the inputs.

Simple example demonstrating the unexpected behavior of apply_changes/1

We have a sample struct. It casts some params then adds a prepare_changes function to that changeset. When calling apply_changes that prepare_changes function is not run so our resulting struct is incorrect.

Example:

defmodule InputData do
  use Ecto.Schema
  @primary_key false
  embedded_schema do
    field :value, :integer
  end
end

%InputData{value: nil}
|> Ecto.Changeset.cast(%{"value" => "1"}, [:value])
|> Ecto.Changeset.validate_number(:value, [greater_than: 0])
|> Ecto.Changeset.prepare_changes(fn changeset ->
  incremented_value = Ecto.Changeset.get_field(:value, 0) + 1
  Ecto.Changeset.put_change(changeset, :value, incremented_value)
end)
|> Ecto.Changeset.apply_changes()

The output of this is not the expected %InputData{value: 2} where the params casts the value to 1 then is incremented again by 1 in the prepare_changes/2. Why is this? Since apply_changes/1 results in a struct and not a changeset there is no risk of firing the prepared_changes functions again if the developer needed to to a Repo insert. In my case I am never inserting this struct into a database and thus need these prepared_changes to run when calling apply_changes.

In summary this feels like a bug or missing implementation in Ecto Changesets that I seem unable to come up with a convincing argument as to why it shouldn’t behave like this.

Most Liked

LostKobrakai

LostKobrakai

The first sentence of the documentation states:

Provides a function executed by the repository on insert/update/delete.

For Ecto.Changeset.apply_changes there’s no repository involved and it’s neither of those mentioned actions either.

Usually prepare_changes is used to execute code within the same transaction as what the changeset applies to the database, which needs to be provided as a callback as that transaction is only started later (by the repo). If you don’t have a transaction you can directly apply the changes to the changeset in place. No need to delay that.

Where Next?

Popular in Questions Top

Tee
can someone please explain to me how Enum.reduce works with maps
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
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
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
Codball
Mix format works fine if run from the cmd. I’ve followed this to facilitate the implementation into VSC which involves downloading an ext...
New

Other popular topics Top

axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 45766 226
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
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
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
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
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
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
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
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
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New

We're in Beta

About us Mission Statement