In pretty much any well designed application, you’ll discover the following phenomenon (among others): dependencies point from the concrete to the abstract.
What would that look like in a Rails application? For starters, Rails would depend on your application, but your application wouldn’t know a damn thing about Rails. In other words, your Gemfile would look like:
gem "rails"
gem "your_app"
“your_app” is an abstraction, containing all of your business logic, but completely unconcerned with concrete details like the UI - or the database. It should, however, define an interface that a data-persistence layer could plug into. We’ll need to update that Gemfile:
gem "rails"
gem "your_app"
gem "some_persistence_layer"
“some_persistence_layer” would depend on “your_app” (so that it can access the persistence interface), but “your_app” would know nothing about “some_persistence_layer”. It’s basically a plugin to your application:
YourApp.persistence = SomePersistenceLayer
So what do you get out of this? For starters, independent deployability. Of course, that doesn’t mean much since you’re packaging it all up with bundler and shipping it out, but there’s a valuable side effect of independent deployability: division of labor. You could have three teams working in parallel - one building the UI, one hammering out the actual app, and one wiring up the persistence layer.
You also stand a decent chance of ending up with a quick test suite, testing each module in isolation from everything else.
Note: I got the ideas in this blog post from watching several episodes of cleancoders.com.