Rails 6 - Multiple Databases

fedeagripa

fedeagripa

Posted on August 19, 2020

Rails 6 - Multiple Databases

Rails 6.0 came up with this amazing enhancement, but for most people, I'm aware they think that is a new feature.
In my opinion, both are correct, because the actual state of multiple databases before rails 6.0 was not even useful to consider it a completed feature.

Let's dive into Rails < 6 state, Rails 6 introduced changes and the current roadmap.

Rails 5 state

Past

ActiveRecord supports multiple databases, but Rails < 6 doesn't provide a way to manage them.
As said you needed to handle everything (yes, everything) in a really manual way, having to create your own tasks for seeds, db:prepare, db:migrate, etc.
Then you needed to create a sort of generator to handle your secondary database migrations following conventions. And finally, as if you hadn't done enough custom work, create an initializer to config your connection to the new database.

So yes, ActiveRecord supported multiple databases, but it was a complete and real mess you didn't want to get into unless really necessary.

Rails 6.0 state

Now

New stuff

  • Multiple primary databases and a replica for each

This is amazing, now you can easiliy configure it in your database.yml like this

development:
  primary:
    database: my_primary_database
    user: root
    adapter: sqlite3
  primary_replica:
    database: my_primary_database
    user: root_readonly
    adapter: sqlite3
    replica: true
  animals:
    database: my_animals_database
    user: animals_root
    adapter: sqlite3
    migrations_paths: db/animals_migrate
  animals_replica:
    database: my_animals_database
    user: animals_readonly
    adapter: sqlite3
    replica: true
Enter fullscreen mode Exit fullscreen mode

Check how you can define your migration paths for each database, and how seem to have the power to have multiple adapters (still working on a POC for this assumption).
An example migration with this would be: rails g migration CreateCats name:string --database animals with this output

  Running via Spring preloader in process 97210
    invoke  active_record
    create    db/animals_migrate/20200819181625_create_cats.rb
Enter fullscreen mode Exit fullscreen mode
  • Automatic connection switching for the model you're working with

You just need to activate it in your middleware for automatic switching:

config.active_record.database_selector = { delay: 2.seconds }
config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
Enter fullscreen mode Exit fullscreen mode

You can also manually decide your connection context:

ActiveRecord::Base.connected_to(role: :reading) do
  # all code in this block will be connected to the reading role
end
Enter fullscreen mode Exit fullscreen mode
  • Automatic swapping between the primary and replica depending on the HTTP verb and recent writes

As we are used to in Rails, this comes standardized:

“If the application is receiving a POST, PUT, DELETE, or PATCH request the application will automatically write to the primary. For the specified time after the write, the application will read from the primary. For a GET or HEAD request, the application will read from the replica unless there was a recent write.“

  • Rails tasks for creating, dropping, migrating, and interacting with the multiple databases

First big comment, the usual rails db:create will now create both databases, as so the usual rails db:migrate will migrate both databases too.
You need to specify which database you want to work with like rails db:create:primary or rails db:migrate:secondary if you want to just modify one.

So for your custom tasks you may need to also specify the desired database you are working with.

Pending ones

  • Sharding
    Right now there are some gems to accomplish this, so until is integrated onto Rails we should keep using gems (no real deal with it)

  • Joining across clusters
    This is what Rails state:
    “Applications cannot join across databases. Rails 6.1 will support using has_many relationships and creating 2 queries instead of joining, but Rails 6.0 will require you to split the joins into 2 selects manually.“

So we just need to wait for rails 6.1!

  • Load balancing replicas
    This seems an interesting feature, so I hope to see upcoming news for this.

  • Dumping schema caches for multiple databases
    Right now this is what is stated:
    “If you use a schema cache and multiple databases you'll need to write an initializer that loads the schema cache from your app. This wasn't an issue we could resolve in time for Rails 6.0 but hope to have it in a future version soon“

So seems like a trivial issue to solve in upcoming versions

Rails 6.1 upcoming state

Upcoming
As you may know, rails 6.1 is almost there so I will double-check what was stated to be released for this new version, and what is actually going to be released

Nice open PRs right now:

So the summary would be:

  • Sharding is now a WIP thing and we may hope to see it live in Rails 6.1
  • Still waiting for the Joining across clusters (or I missed it in my review)
  • Still waiting for load balancing
  • Schema caches are now a thing!

Some personal ideas

Dreams

I'm a huge fan of non-relational databases, so I would love to see some mixins of MongoDB + Postgres for example. And with this introduced changes I think that the road is prepared enough to start working on a way to properly work with it.
My doubts are more into "Should ActiveRecord really support non-relational databases?" or "Is something more rails work outside ActiveRecord?". Leave your thoughts and I will be more than happy to chat over it :)

💖 💪 🙅 🚩
fedeagripa
fedeagripa

Posted on August 19, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Rails 6 - Multiple Databases
rails Rails 6 - Multiple Databases

August 19, 2020