Exporting to CSV in Rails 6 multi DB setup

Expected behavior

To export table data from current db connection to CSV

Actual behavior

Table from the default db table is exported.

Context

Rails 6.1.3.1
Forest Liana 6.3.1

We have a rails 6 app, with a mutli db (horizontal sharding) setup.

We have implemented a smart action so the end user can select which db they want to connect to.

Then an around_action callback is performed by overriding ForestLiana::BaseController.
The action has code analogous to:

ActiveRecord::Base.connected_to(role: :writing, shard: shard) do
   yield
end

This works well, and ensures the controller action is executed in the context of the correct db connection.

However, when exporting the table data to csv, the default db connection is always used.

Can someone provide insight into this behaviour?

Many thanks

Hello @veritas1,

It seems that your use case is very specific and out of our usual scope.
Are you willing to share your code in order for us to try to understand more and investigate?

Thank you

Yes. What would you like?

Hi @veritas1,

The smart action allowing this DB switch, alongside the ForestLiana::BaseController override you seems to have made might help us dig into this.

We can take a look to try and find something that might have gone wrong with your data export. But by overriding forest base controller and having a smart action dynamically changing your db connection, you’re changing forest’s original behavior and this kind of issues might be out of the scope of what we can help you with.

Best regards

The smart action just writes the user selected db connection to a file.

Here is the base controller:

ForestLiana::BaseController.class_eval do

  around_action :set_database_connection

  def set_database_connection
    yield and return if defined?(forest_user).nil?
    user_id = forest_user['id']
    yield and return if user_id.nil?

    file_path = File.join(Rails.root, DB_CONNECTIONS_FILE)

    data = File.read file_path
    hash = eval data

    user_db_connection = hash[user_id]
    yield and return if user_db_connection.nil?

    Rails.logger.info "Admin panel connecting to database: #{user_db_connection}"

    ActiveRecord::Base.connected_to(role: :writing, shard: user_db_connection.to_sym) do
      yield
    end
  end
end

Thank you for sharing this with us, if I understand well, this configures a custom connection for each user when they are querying on your admin panel. I have two questions then:

  • Does that work for the all app except the export (listing values, dashboards, smart actions, etc)?
  • When exporting, is the queried DB the one you defined by default through your env variables?

Thank you

Yes. Everything tested so far like listing values, dashboards, smart actions all work as expected e.g. the correct database connection is used.

No. It is not using the database specified in the DATABASE_URL env variable. It is using the first database defined in the config e.g shard1 as per the below.

production: &production
  shard1:
    <<: *default
    database: defaultdb
    url: <%= ENV["SHARD_1_DATABASE_URL"] %>
    prepared_statements: false
    advisory_locks: false
  shard2:
    <<: *default
    database: defaultdb
    url: <%= ENV["SHARD_2_DATABASE_URL"] %>
    prepared_statements: false
    advisory_locks: false
  shard3:
    <<: *default
    database: defaultdb
    url: <%= ENV["SHARD_3_DATABASE_URL"] %>
    prepared_statements: false
    advisory_locks: false

Hello @veritas1,

I’ve dig into our code. The good news: It should work.

To be honest, I don’t see any reason your code is not working on this specific case.

So, can you debug your code and look at the forest_user and user_id. In order to know if in the case of Exporting to CSV they are well defined.

Best regards,
Morgan