'Best practice for similar repeated queries using ActiveRecord

I have a couple simple queries and I'm not sure what the best practice is.

I've written them in 2 ways which produce the same result. Which is preferred? Or is there a third, better way?

More concise:

Fruit.where(id: NOT_PREPACKAGED_RAW_FRUIT_IDS).update_all(prepackaged_raw_enabled: false)
Fruit.where.not(id: NOT_PREPACKAGED_RAW_FRUIT_IDS).update_all(prepackaged_raw_enabled: true)

More verbose:

fruits = Fruit.all
not_prepackaged = fruits.where(id: NOT_PREPACKAGED_RAW_FRUIT_IDS)
prepackaged = fruits - not_prepackaged
not_prepackaged.update_all(prepackaged_raw_enabled: false)
prepackaged.update_all(prepackaged_raw_enabled: true)

The purpose of the snippet is to do a onetime backfill.



Solution 1:[1]

If you want to do it in a single statement/query, you can write it like this:

Fruit.update_all(prepackaged_raw_enabled:
  Fruit.arel_table[:id].not_in(NOT_PREPACKAGED_RAW_FRUIT_IDS)
)

If NOT_PREPACKAGED_RAW_FRUIT_IDS = [571, 572], that would translate to the following SQL, which will update all of the records at once:

UPDATE "fruits" 
SET "prepackaged_raw_enabled" = "fruits"."id" NOT IN (571, 572)

Solution 2:[2]

Without any more context, your first example is easier to follow. Assuming you want to touch every single record, it might improve clarity (although would be a little slower) if you backfill all records, then just the subset:

Fruit.update_all(prepackaged_raw_enabled: true)
Fruit.where(id: NOT_PREPACKAGED_RAW_FRUIT_IDS).update_all(prepackaged_raw_enabled: false)

Or maybe it's safer for your setup to do it the other way around (although the double negative is not ideal):

Fruit.update_all(prepackaged_raw_enabled: false)
Fruit.where.not(id: NOT_PREPACKAGED_RAW_FRUIT_IDS).update_all(prepackaged_raw_enabled: true)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 BenFenner