Modifying a has_many association to include nils

posted in: Tech | 0

I had this interesting use case come up.

We have a multi-tenant app that has an Organization  model. An Organization has many BarcodeItem.

Originally, the query was direct: We only wanted an instance of Organization  to return the barcode_items  that belonged to it.  Then we decided to pivot on this particular feature and have an organization include both its own barcode_items  but also any BarcodeItem  that was explicitly set to nil . The idea here was that some BarcodeItem  would be “global”, and the simplest way to do that would be to de-associate them from any Organization.

So I started with a simple spec to test this out:

My first thought was to use an association model, something like:

But even after just writing that it just smelled wrong. Surely there’s an easier way to do this. Consulting the docs, I was reminded of using association scopes. So I tried this instead:

Still fails. I needed to see what it’s actually doing behind the scenes, so I dumped the SQL before the test:

RSpec displayed the query as:

SELECT “barcode_items”.* FROM “barcode_items” WHERE “barcode_items”.”organization_id” = 4 AND (“barcode_items”.”organization_id” = 4 OR “barcode_items”.”organization_id” IS NULL)
returns both this organizations barcodes as well as global ones (FAILED – 1)

A-ha!

The additional scoping added to the association is a boolean AND, but we need a boolean OR. After several failed attempts at mimicking that functionality, I found a StackOverflow answer that suggested unscoping the query first.

Success!