Different widget related front-end views will need different fields and relations (like widget prices, widget categories, user widget history and so on).
There are lots of different solutions:
- Over fetching. /widgets/123 returns not only all the fields for a widget, but more or less every possible relation. So a single API call can support any view, but with the downside that the payload contains far more data than is used by any given view. This not only increases bandwidth but usually also load on the database.
- Lots of API calls. API endpoints are tightly scoped and the front-end picks whichever endpoints are needed for a given view. One view calls /widgets/123 , /widgets/123/prices and /widgets/123/full-description. Another calls /widgets/123 and /widgets/123/categories. And so on. Every view only gets the data it needs, so no over fetching, but now we're making far more HTTP requests and more database queries.
- Tack a little "query language" onto your RESTful endpoints. Now endpoints can do something like: /widgets/123?include=categories,prices,full-description . Everyone gets what they want, but a lot of complexity is added to support this on the backend. Trying to automate this on the backend by having code that parses the parameters and automatically generates queries with the needed fields and joins is a minefield of security and performance issues.
- Ditch REST and go with something like GraphQL. This more or less has the same tradeoffs as the option above on the backend, with some additional tradeoffs from switching out the REST paradigm for the GraphQL one.
- Ditch REST and go RPC. Now, endpoints don't correspond to "Resources" (the R in rest), they are just functions that take arguments. So you do stuff like `/get-widget-with-categories-and-prices?id=123`, `/get-widget?id=123&include=categories,prices`, `/fetch?model=widget&id=123&include=categories,prices` or whatever. Ultimate flexibility, but you lose the well understood conventions and organization of a RESTful API.
After many years of doing this lots of time, I pretty much dislike all the options.
If you just have one single monolithic database, anything clever you do on the other levels just lets you survive until the single monolithic database becomes the bottle-neck, where unexpected load in one endpoint breaks several others.
But yeah, rails might be a bad match
When a project is new and small, whatever approach I take feels amazing and destined to work well forever. On big legacy projects or whenever a new project gets big and popular, whatever approach I took starts to feel like a horrible mess.
Rails' initial rise in popularity coincided with the rise of REST so these patterns spread widely and outlasted Rails' mindshare
That's what https://guides.rubyonrails.org/association_basics.html is for.
However, Rails scaffolding is heavily geared towards that 1:1 mapping - you can make all CRUD endpoints, model and migration with a single command.