Rootstrap Blog

Feature Updates in Rails 6: Multiple Databases & State Management

Rails 6.0 recently shared its amazing enhancements, though most would consider these feature upgrades.

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

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 seedsdb:preparedb: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

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

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
  • 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

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
  • Automatically 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

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

I’m a huge fan of non-relational databases, so I would love to see some mixins of MongoDB + Postgres for example. With the introduced changes I think we can soon find a way to properly work with it.

My doubts are “Should ActiveRecord support non-relational databases?” or “Is something more rails work outside ActiveRecord?”

Would love to hear your thoughts. Feel free to leave a comment or connect with me about this topic!

0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.