patrickdm

patrickdm

How to use Ecto optimistic_lock with Phoenix generated update action?

Hello,
I’ve been trying to implement Ecto.Changeset.optimistic_lock in a Phoenix application but I’m stuck with the generated controller’s update action.

In iex I have success rising an Ecto.StaleEntryError when I try to update a stale record, (as shown in the documentation):

iex> post = Repo.insert!(%Post{title: "foo"})
%Post{id: 1, title: "foo", lock_version: 1}
iex> valid_change = Post.changeset(:update, post, %{title: "bar"})
iex> stale_change = Post.changeset(:update, post, %{title: "baz"})
iex> Repo.update!(valid_change)
%Post{id: 1, title: "bar", lock_version: 2}
iex> Repo.update!(stale_change)
** (Ecto.StaleEntryError) attempted to update a stale entry

here the two changeset are being generated from the same post struct, and Repo.update raise the expected error.

On the other hand, when the update is performed concurrently in two browser windows, -my understanding is that- the controller’s update action performs a new get_post!(id) and then uses that struct to make the update’s changeset, with the form params; therefore the latest update is always overwriting the first occurring, thus making optimistic_lock useless in this context.

I couldn’t find much help on this issue, and it make me think I’m getting all this wrong.. Thank’s for any help.

Marked As Solved

1player

1player

That’s an interesting question. Disclaimer: I’ve never used optimistic_lock.

Since lock_version is just a regular field, one idea would be to pass, alongside with the ID, the version of the object in the update method and using that version before you apply any changes.

Example, in your form:

<form action="<%= Routes.post_path(@conn, :update, @post) %>" method="POST">
  ...
  <input type="hidden" name="post[lock_version]" value="<%= @post.lock_version %>"> 
</form>

And in your controller:

def update(conn, %{"id" => id, "post" => %{"lock_version" => lock_version}}) do
  post = 
    id
    |> Posts.get_post!()
    |> Map.put(:lock_version, lock_version)

  ...
end

Now you will will get a StaleEntryError if you’re updating an old post.

EDIT: you might want to use hidden_input to generate the hidden field instead of doing it manually

Where Next?

Popular in Questions Top

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
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
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
tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
nobody
How to bind a phoenix app to a specific ip address? could not find anything about that, nowhere, unfortunately, but for me this is quite...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
yawaramin
In the Dialyzer docs ( dialyzer — OTP 29.0.2 (dialyzer 6.0.1) ), there is a way to turn off a specific warning for a function: -dialyzer...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New

Other popular topics Top

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
malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43622 214
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
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New

We're in Beta

About us Mission Statement