Back to Course

Spot the Tax · Card 4 of 20

JSON-as-text blocks the queries you'll need later

Why serialize :metadata, JSON is fine until someone asks for a report.

The code

What will this cost you in six months?

class Order < ApplicationRecord
  serialize :metadata, JSON
end

# Writing:
order.metadata = { plan: "pro", referrer: "google", utm_campaign: "spring" }
order.save

# Reading later, in a report:
Order.where("created_at > ?", 90.days.ago).select do |o|
  o.metadata["plan"] == "pro"
end

The problem

The metadata column is just a regular text column that happens to contain JSON. As far as the database is concerned, the whole field is one opaque string. Writing a hash to it serializes the whole thing to a JSON string and stores it as text, and reading it back parses the string into a hash again. As long as you're only ever loading or saving a single record, that's fine. But as soon as you need to query inside the metadata — like asking "how many orders had plan = 'pro' last quarter" — the database can't help, because it has no way to look inside a text field. So every row has to be loaded, every JSON string has to be parsed in Ruby, and the filtering has to happen in your application instead of in the database.

Take a moment. Before revealing, think about how you'd actually answer the report's question. What would you change about the schema so the database could help you?