Raw sql is not composable.
This seems like the biggest trend the more I use RAILs: it’s great to iterate and prototype, but as soon as you hit scale the maintainability becomes a big issue. I’m not saying other web frameworks are immune or that this is a problem that cannot be solved, it’s just all of these abstractions and cascade of configuration objects to make RAILs do what you want end up getting in the way.
A query builder is the best of both worlds: semantics that resemble raw SQL with some ability for composition.
# Boilerplate
from sqlalchemy import create_engine, MetaData, Table
engine = create_engine('sqlite:///:memory:', echo=True)
metadata = MetaData()
customers = Table('customers', metadata, autoload_with=engine)
query = customers.select([customers.c.id, customers.c.fname, customers.c.lname, customers.c.phone])
# => SELECT customers.id, customers.fname, customers.lname, customers.phone FROM customers
conn = engine.connect()
conn.execute(query)
# => [(1, "Foo", "Bar", "12345678"), ...]
ActiveRecord also has Arel which can be use as a standalone. Documentation is a bit more sparse compared to SQLAlchemy Core or its ActiveRecord ORM counterpart, though.