The client
Glaser Mills is a US-based textile converter. They buy unfinished fabric — greige goods — directly from mills, then oversee the dyeing, printing, and finishing processes to create marketable fabric for their customers.
RemoteCore has worked with Glaser Mills for decades. We inherited the project when their inventory management system was running on Rails v1 — custom-built, production-critical, and deeply woven into how the business operated. Over the years we handled the upgrades to Rails v4 and later v6, along with ongoing maintenance, feature development, and moving the app to Heroku.
The problem
Heroku announced the end-of-life of the stack the app was running on. Once that date passed, all new releases would be blocked — no bug fixes, no features, nothing. It wasn't optional: the app had to move.
But the upgrade surface was significant. The app was running several versions behind on both Ruby and Rails. The frontend was the biggest challenge: built with Bootstrap 4, jQuery, and heavy use of jQuery DataTables — an architecture that had served well for years but had grown difficult to maintain and extend.
A forced infrastructure migration is rarely a good time to also modernise the frontend. But the alternative — upgrading just enough to unblock deploys and deferring the real work — would have left the team with the same painful codebase and a bigger upgrade ahead of them later.
The client decided to use the deadline as a catalyst. If they were doing a major upgrade anyway, they wanted to come out the other side with something they could actually build on.
The solution
We upgraded to Rails 8 and took full advantage of what that version introduced. Rails 8 ships with Hotwire — specifically Turbo — which fundamentally changes how server-rendered Rails apps handle interactivity. Rather than reaching for JavaScript for every dynamic behaviour, Turbo handles page transitions and partial updates natively. It gave us most of what jQuery was doing, without the weight.
For the frontend, we replaced Bootstrap 4 and jQuery with Tailwind CSS and rewrote the UI from the ground up. Tailwind's utility-first approach fit well with a team that cares about tight control over the visual output. The component surface became smaller and easier to understand.
For highly interactive pages — the kind that genuinely needed a rich client-side component model — we chose Vue.js over Stimulus. Stimulus is fine for simple behaviours sprinkled onto server-rendered HTML, but for the complexity in some of Glaser Mills' workflows, Vue gave us the structure we needed without adding significant overhead.
We avoided Stimulus in favour of Vue.js for complex interactions — Stimulus is pragmatic for simple enhancements, but Vue gave us a proper component model where we actually needed it.
We also used Cursor AI to accelerate the development process, particularly for the repetitive parts of the migration. The codebase had a significant amount of CoffeeScript and HAML — both reasonable choices when they were written, but no longer the right defaults. We converted the CoffeeScript to modern JavaScript and the HAML templates to ERB, using Cursor to work through the conversion at scale. Migrating jQuery DataTables to modern equivalents and converting Bootstrap layout patterns to Tailwind utilities also benefited from AI-assisted editing. It worked well.
We also moved the deployment off Heroku onto an AWS EC2 instance. Heroku had scaled back the services available on our tier, so rather than work around the limitations we took the opportunity to move to EC2 for better control over the environment.
The result
The app is fully current: latest stable Ruby, Rails 8, a clean Tailwind frontend, and a deployment pipeline that isn't blocked by infrastructure EOL. Glaser Mills can deploy again, and the team has a codebase that's significantly easier to work in than what they had before.
The stack — Rails 8, Turbo, Tailwind, Vue where needed — gave us everything we wanted: good developer experience, fast page interactions, and the flexibility to build out new features without fighting the framework. For a business-critical internal tool that needs to keep working reliably, that combination proved to be a solid choice.
The engagement is ongoing. That's usually the best sign.