[Talking-Ruby] Use Foreign Data Wrappers in Rails
Use Foreign Data Wrappers in Rails
Foreign Data Wrappers is a fantastic feature of PostgreSQL that allows you to query against external data sources. The external data source is not just a different Postgres database - it could be anything as long as the appropriate extension is available for that particular data source. You can make it work with MySQL
, Redis
, MongoDB
, and even Kafka
, so the flexibility is quite impressive. Nevertheless, let’s focus on Postgres-to-Postgres integration, which is available out of the box.
The idea behind FDWs is quite simple:
-
Enabling the extension
-
Define an external server
-
Define the user mapping of how to access that server
-
Create or import foreign tables, which are adapter/proxy-like tables to an external data source.
-
Run queries against just yet another table - it will just be a table with some extras compared to a standard one.
Now that we know the basics let’s see how we could use it in a Rails application.
Usages
Imagine that we have some OrderStat model in our current app, and we need some data from the Order model represented by the “orders” table from a different database.
We will need fews migrations to make it work.
Enabling the extension
First, let’s create the extension:
1 | class CreateFdwExtension < ActiveRecord::Migration[6.1] |
Define an external server
Next, let’s create a server:
1 | class CreateFdwServer < ActiveRecord::Migration[6.1] |
Define the user mapping of how to access that server
we will need to provide the user and password to access that foreign DB:
1 | class CreateFdwMapping < ActiveRecord::Migration[6.1] |
Create or import foreign tables
One way of doing this is via CREATE FOREIGN TABLE orders
where you provide the exact schema for this table, but this is not efficient for a large number of columns. It’s way more convenient to use IMPORT FOREIGN SCHEMA
where you can provide the schema name (unless you went with some custom solution, just use “public” here), name of the table(s), and name of the server, and that’s it! You don’t need to bother with the exact columns and their types and constraints.
1 | class CreateForeignAccountsTable < ActiveRecord::Migration[6.1] |
And that’s it!
You could test it using joins:
1 | # assuming that OrderStat and Order models exist in the app and OrderStat belongs to Order |
And that’s how you join tables from two different databases :). However, to make it fully work in your Rails app, so that you can, for example, execute simple queries like OrderStat.joins(:order).first.order, you might need one adjustment in the Order
model with explicitly specifying the primary key, as otherwise, you might get the following error:
1 | ActiveRecord::UnknownPrimaryKey (Unknown primary key for table orders in model Order.) |
So here it is:
1 | class Order < ApplicationRecord |
And that’s it!
Refreshing schema
It’s quite likely that the schema of the “orders” table will change. In such a case, if you need to refresh the schema, just recreate foreign tables.
References
[3] Foreign data wrappers - PostgreSQL wiki - https://wiki.postgresql.org/wiki/Foreign_data_wrappers