I can't figure out how to tell rails to SELECT ... FOR UPDATE
on multiple rows. Poking around in console, Foo.where(bar: "baz").lock
does produce the right SQL. But when I try to do it in a transaction, that ruby code doesn't actually generate the SQL. I think the one-off is working because the rails console automatically runs .all
on the relation to display the results.
Here's what I run in console
Foo.transaction do
Foo.where(bar: "baz").lock
Foo.where(bar: "baz").update_all(bar: "baz2")
end
and the SQL:
BEGIN
Foo Update All (0.5ms) UPDATE "foos" SET "bar" = $1 WHERE "foos"."bar = $1 [["bar", "baz2"]]
COMMIT
If I change the lock line so that rails thinks that it needs to do somthing with the collection, like add puts
to the beginning or pluck
to the end...
Foo.where(bar: "baz").lock.pluck(:id)
...then I do get the expected FOR UPDATE
query before the update happens, with the expense of having to pipe the result over the wire and put it into memory and then do nothing with it.
So it seems that rails properly uses .lock
to modify the SQL of the relation, but there's no elegant way to actually invoke the lock. Am I doing something wrong or do we need to use some sort of workaround (like pluck
) to get the query to happen?