Spree::Brand model with everything it needs: a name column, a rich text description, and an uploadable logo.
Step 1: Generate the Model
Spree ships aspree:model generator that produces a model and migration following all Spree conventions — Spree:: namespacing, prefixed IDs, presence validations, and API filtering allowlists. It understands Rails attribute types including the virtual ones, so rich text and file attachments are part of the same command:
Throughout this tutorial every command is shown in two forms. Spree CLI is for projects created with create-spree-app, where the app runs in Docker and
spree <command> routes into the container. Without Spree CLI is for apps running Spree backend directly on your machine.app/models/spree/brand.rb— the modeldb/migrate/XXXXXXXXXXXXXX_create_spree_brands.rb— the migration
spree_brands table with an indexed name column. The description and logo attributes don’t add columns — rich text lives in Action Text’s action_text_rich_texts table, and uploads live in Active Storage’s tables.
Step 2: Understand the Generated Model
Openapp/models/spree/brand.rb:
app/models/spree/brand.rb
Spree.base_class— inherits all Spree model functionality (multi-store scoping helpers, preferences, and more). The class is namespaced underSpree::, so it’s available asSpree::Brand.has_prefix_id :brand— records get Stripe-style public IDs likebrand_k5nR8xLq. APIs never expose raw database IDs.has_rich_text :description— formatted content via Action Text.has_one_attached :logo— file uploads via Active Storage, with image processing and direct-to-storage uploads.validates :name, presence: true— generated automatically for required columns.whitelisted_ransackable_attributes— controls which attributes API clients may filter and sort by. Only allowlisted attributes are queryable, so addingnamehere is what later makes?q[name_cont]=nikework.

