Home > Blockchain >  Create data in additional databases in Rails application
Create data in additional databases in Rails application

Time:12-01

In my rails(version 6.1.3.2) application I have 2 databases:

  1. primary, for most models
  2. api_logs, for ApiLog model And my database.yml looks like:
development:
  primary:
    <<: *default
    database: <%= ENV["DB_NAME"] || 'jspro_development' %>
    host:  <%= ENV["DB_HOST"] || 'localhost' %>
    username: <%= ENV["DB_USERNAME"] || 'postgres' %>
    password: <%= ENV["DB_PASSWORD"] || 'postgres' %>
    port: <%= ENV["DB_PORT"] || '5432' %>
  api_logs:
    <<: *default
    database: <%= ENV["API_LOGS_DB_NAME"] || 'api_logs_development' %>
    host:  <%= ENV["API_LOGS_DB_HOST"] || 'localhost' %>
    username: <%= ENV["API_LOGS_DB_USERNAME"] || 'postgres' %>
    password: <%= ENV["API_LOGS_DB_PASSWORD"] || 'postgres' %>
    port: <%= ENV["API_LOGS_DB_PORT"] || '5432' %>
    migrations_paths: db/api_logs

And my ApiLog model has the following migration:

class CreateApiLogs < ActiveRecord::Migration[6.1]
  def change
    create_table :api_logs do |t|
      t.timestamps
      t.string :method
      t.string :path
      t.string :query_string
      t.json :headers, default: {}
      t.json :request_body, default: {}
      t.string :remote_address
      t.string :http_origin
      t.integer :response_status
      t.string :http_user_agent
      t.string :http_referer
      t.integer :user_id
      t.integer :account_id
      t.string :membership_type
      t.string :unique_id
    end
  end
end

The databases were both created and migrated successfully. And in my app/models/api_log.rb I have the following declaration:

# frozen_string_literal: true

class ApiLog < ApplicationRecord
  self.table_name = 'api_logs'
  self.abstract_class = true

  connects_to database: { writing: :api_logs, reading: :api_logs }
end

With this I am able to run read queries like:

irb(main):002:0> ApiLog.first
  ApiLog Load (1.6ms)  SELECT "api_logs".* FROM "api_logs" ORDER BY "api_logs"."id" ASC LIMIT $1  [["LIMIT", 1]]
=> nil
irb(main):003:0> ApiLog.count
   (2.1ms)  SELECT COUNT(*) FROM "api_logs"
=> 0

And they're fine.

But when I try to create one:

irb(main):003:0> ApiLog.count
   (2.1ms)  SELECT COUNT(*) FROM "api_logs"
=> 0
irb(main):004:0> ApiLog.create(method: 'POST', user_id: 61)
Traceback (most recent call last):
        1: from (irb):4
NotImplementedError (ApiLog is an abstract class and cannot be instantiated.)

I understand the error is complaining about this being an abstract class due to the declaration in the model. However, if I remove self.abstract_class=true, even ApiLog.count no longer works:

irb(main):001:0> ApiLog.count
Traceback (most recent call last):
        3: from (irb):1
        2: from app/models/api_log.rb:3:in `<main>'
        1: from app/models/api_log.rb:7:in `<class:ApiLog>'
NotImplementedError (`connects_to` can only be called on ActiveRecord::Base or abstract classes)

I've followed the Rails guide and it doesn't see to work, even though the read queries are fine.

So how do I create api_logs objects in the new database?

Thanks!

CodePudding user response:

From the Rails guide:

Your issue is that you are trying to make a single class act as both your model and what the Guide calls the connection model.

It's important to connect to your database in a single model and then inherit from that model for the tables rather than connect multiple individual models to the same database.

I believe you just need to separate what you've got into two models:

class LogRecord < ApplicationRecord
  self.table_name = 'api_logs'
  self.abstract_class = true

  connects_to database: { writing: :api_logs, reading: :api_logs }
end

class ApiLog < LogRecord
...
end

The only reason the read queries seem to work the way you have it is you don't have any matching records and therefore the result is nil. If there was an existing record you'd get the same error as for create because this issue is not with the SQL query, it's with the resulting instantiation of your class.

  • Related