class OrdersController < ApplicationController
def index
@orders = Order.by_payment_method(params[:payment_method]).above_amount(params[:amount])
end
def update_metadata
order = Order.find(params[:id])
order.update_metadata(params[:key], params[:value])
redirect_to orders_url
end
end
class AddMetadataToOrders < ActiveRecord::Migration[7.0]
def change
add_column :orders, :metadata, :jsonb, default: {}, null: false
add_index :orders, :metadata, using: :gin
end
end
class Order < ApplicationRecord
validates :metadata, presence: true
scope :by_payment_method, ->(method) { where("metadata ->> 'payment_method' = ?", method) }
scope :above_amount, ->(amount) { where("CAST(metadata ->> 'amount' AS NUMERIC) > ?", amount) }
def payment_method
metadata["payment_method"]
end
def update_metadata(key, value)
update(metadata: metadata.merge(key => value))
end
end
This snippet uses PostgreSQL’s JSONB column to store flexible metadata for orders, making it easy to store dynamic attributes without schema changes. The scopes allow efficient filtering using native SQL JSON functions. The update_metadata
method enables seamless updates without overwriting existing data.
Martin Sojka, Maker of CodeSnips