saverio-kantox
Ecto/Postgres/Phoenix set session variable on checkout connection
I need to set up a “audit” table in the database, where changes to records trigger an insert on some other table. Writing the trigger is not an issue.
Ideally, I would try to store also some sort of “current user” on the audit, which is known for instance in a specific plug. Here is the issue: I see no way to tell Ecto that all connections that are checked out from the pool should have an “initial” command sent like set session 'myapp.current_user' = 'abcdef12-1234-1234-12345678abcdcdef';.
The problem is threefold:
- How to hook into connection checkout
- How to ensure that the connection is not held for too much time
- How to pass it down for instance to a liveview (maybe it’s just a restatement of 1+2, because the liveview is long-lived, and the connection should not be held)
Does anyone have any suggestion on how to approach the problem?
Than you beforehand!!
Marked As Solved
idi527
Or add audited_insert to the default repo:
defmodule MyApp.Repo do
# ... use Ecto.Repo, blah blah
defp audited(op, %User{} = user, args) do
transaction(fn ->
query("set session 'myapp.current_user' = '#{user.id}';")
apply(__MODULE__, op, args)
end)
end
def audited_insert(changeset, user, opts \\ []) do
audited(:insert, user, [changeset, opts])
end
# ... no need for defedelegates
end
Also Liked
halostatue
The hex.pm source has a really good audit logging implementation that is worth looking at. I’ve been running a (heavily modified) variant of it in production for the last couple of years and it hasn’t failed me yet. It has a Task-based audit function that can be used for writing to the audit log on reads. I’m sure it wouldn’t be hard to write your error handling to use the audit function if, say, a multi operation failed.
wolfiton
If you need videos my search was successful and found a lot but that specific one eludes me as well.
In any case if you want eleixir conf videos this is what I found https://www.youtube.com/results?search_query=elixir+conf
Maybe this might help:
-
Also I am wondering if not the ecto multi, can be used here. https://hexdocs.pm/ecto/Ecto.Multi.html.(can make several repo actions like multiple inserts)
-
The changeset also can prepare queries and add to them.
Ecto.Changeset — Ecto v3.14.0(modify structures and validate them)
danschultzer
I’m not sure if this is a good way of doing it, but you could create a custom repo module, and require the user id to be passed along:
defmodule MyApp.AuditedRepo do
alias MyApp.Repo
@spec insert(Ecto.Changeset.t(), binary() | nil, keyword()) :: {:ok, map()} | {:error, Ecto.Changeset.t()}
def insert(changeset, user_id, opts \\ []) do
Repo.transaction(fn ->
# set session here
Repo.insert(changeset, opts)
end)
end
# all other methods, e.g. using defdelegate for the actions that doesn't need user id
end
So in the context methods you’ll have to pass along the user id:
defmodule MyApp.Posts do
alias MyApp.{AuditedRepo, Posts.Post}
def create_post(user_id, attrs) do
%Post{}
|> Post.changeset(attrs)
|> AuditedRepo.insert(user_id)
end
# ...
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









