Kicking off an Oban job in the same transaction as an action

rohan
2023-04-08

rohan:

What’s the right way to kick off an oban job in the same transaction as for example creating an ash?

ZachDaniel:

Yep! So unless you say otherwise ( transaction? false in action definition), all create/update/destroy actions will open a transaction by default. As long as you are using the same repo between oban and your resources, then it should “just work” in an after action or before action hook.

ZachDaniel:

before/after action hooks will run in the same transaction as the parent

rohan:

is that the right idiom to use for something like kicking off oban tasks?

rohan:

as in - before/after action hooks

ZachDaniel:

yes, absolutely.

rohan:

awesome

rohan:

the other thing I’m a little confused about is whether before action hooks run before validations

rohan:

it seems like they run after allow_nil gets checked on attributes - is that right?

ZachDaniel:

correct. before_action hooks happen “just before” the action is actually committed, after validation and things like that.

rohan:

is there another hook that runs before the validations

ZachDaniel:

The lifecycle is laid out in that guide.

ZachDaniel:

When you say validations, do you mean validate in the resource/action? Or do you mean allow_nil? being validated?

ZachDaniel:

I assume you’re setting some required attribute in a before_action hook or something like that?

rohan:

yup it’s a slightly different use case but essentially I’m doing a file upload (from a binary) and then grabbing the url (which is required in the db) after that

rohan:

I think after reading the lifecycle I just need a regular old change , not a before_action

ZachDaniel:

If you are doing a file upload, I’d suggest doing it in a before_action hook

ZachDaniel:

or a before_transaction hook

ZachDaniel:

The way to think about it is that an action’s changes might be run many times potentially (like if used with AshPhoenix.Form )

rohan:

ah I see

rohan:

the issue i’m having with the before_action hook is that the file_url shouldn’t be nil

ZachDaniel:

To do what you want, though, there are a few different options

ZachDaniel:

create :create do
  allow_nil_input [:file_url]
end

rohan:

ah!

ZachDaniel:

allow_nil_input says “this thing that is normally required is not required”

ZachDaniel:

However, you can also just define the inputs that are “accepted” by the action. In 3.0 this will be a requirement actually. However, until then, the default behavior remains which is that all actions accept all public, writable attributes.

ZachDaniel:

create :create do
  accept []

  argument :file_data, :binary do
    allow_nil? false
  end
end

ZachDaniel:

If an input isn’t accepted by an action, we assume that you will set it at some point in your action (but validate just prior to submission still)

rohan:

got it

rohan:

that seems better than allow_nil_input which could potentially allow nil input through if I mess up my before_action in some way

ZachDaniel:

I agree that it is better because it makes the action more clearly defined, but allow_nil_input only allows nil input, not nil values in the actual action submission.

rohan:

oh ok that makes sense haha

rohan:

thanks!

ZachDaniel:

👍

ZachDaniel:

My pleasure

rohan:

ash seems super powerful but it’s taking me a while to grok

rohan:

it reminds me “fat models” in rails which i was a fan of.. write everything only once

ZachDaniel:

Yep! I have lots of problems with ruby/rails from an execution standpoint, but ultimately the goal is to have singular definitions that lots of behavior can be derived from.

ZachDaniel:

And the bigger/more variated your system is, the more that pays off.

ZachDaniel:

I’ve kicked off the “Ash Primer” youtube series, so maybe I’ll do next weeks video on the action lifecycle 🙂