"You have to specify your fields at compile time" is exactly not like ActiveRecord, though. That's exactly the downside to it for doing ActiveRecord.
At that point, you may (should) just use an object mapper like ROM that has no model-class hooks at all. (Which I actually like. But the Rails world disagrees.)
You effectively do specify your fields before runtime in Rails, though, in the form of your migrations. Furthermore all of the associations (belongs_to, etc), are arguably also specified before runtime since those helpers run when the class is parsed.
I frequently don't use Ruby-based migrations. I use datastores defined elsewhere and use Sequel as a convenient and easy interface for tasks against those datastores.
You're trying to slice too fine. Crystal can't do this. That's OK. Own it, don't try to hide it.
https://github.com/amberframework/granite-orm https://github.com/sam0x17/crystal-mongo-orm