Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to execute a transaction with the model? #379

Open
Nicolab opened this issue Feb 6, 2020 · 4 comments
Open

How to execute a transaction with the model? #379

Nicolab opened this issue Feb 6, 2020 · 4 comments

Comments

@Nicolab
Copy link

Nicolab commented Feb 6, 2020

Hello,

I am trying to execute a transaction with the model.

It works:

User.adapter.database.transaction do |tx|
  # here the lang is "en"
  ret = tx.connection.exec "UPDATE users SET lang=$1 WHERE id=$2", "fr", 17
  tx.rollback
  puts "rollback"

  # Ok, here the lang is "en" again
   pp User.find 17
end

It does not work:

User.adapter.database.transaction do |tx|
  user = User.find 17
  break unless user

  # here the lang is "en"
  user.update lang: "fr"

  tx.rollback
  puts "rollback"

  # here the lang is "fr" (updated)
  pp User.find 17
end

Where am i wrong? Maybe I need to pass the tx.connection to the User model?

@msa7
Copy link
Contributor

msa7 commented Jun 10, 2020

any updates here?

@kalinon
Copy link
Contributor

kalinon commented Apr 26, 2023

There does not seem to be any support for transactions via Granite models.

Nor does there seem to be a way to have the model use the transaction connection for its changes. It defaults to using the models adapter connection, which is why the transaction cannot be rolled back.

@crimson-knight
Copy link
Member

Thank you @kalinon

I think that supporting transactions is important, so I've labeled this as part of bringing Granite up to feature parity with ActiveRecord and added the label for this being an enhancement.

@kalinon
Copy link
Contributor

kalinon commented Apr 26, 2023

Just some further comments on how this example is working:

# TX comes from the DB shard not granite
User.adapter.database.transaction do |tx| 
  user = User.find 17
  break unless user

  # here the lang is "en"
  user.update lang: "fr"  # This update uses a different connection which is not having a `transaction` happening

  tx.rollback           # This performs a rollback but on the `tx` connection
  puts "rollback"

  # here the lang is "fr" (updated)
  pp User.find 17
end

when you get to User.adapter.database its no longer in Granite

So if we wanted this behavior we would need to build a whole transaction feature, where any DB action within the block, would use that connection. Allowing a rollback to occur.

he was able to roll back in his first example because hes calling the tx directly:

  ret = tx.connection.exec "UPDATE users SET lang=$1 WHERE id=$2", "fr", 17
  tx.rollback

This feature would probably require some sort of mechanism that checks what thread you are in, and gives you the same connection. However, it would need to probably be implemented on a Granite call (i.e User.transaction) and not via the DB lib.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants