In my rails(version 6.1.3.2) application I have 2 databases:
- primary, for most models
- api_logs, for
ApiLogmodel And mydatabase.ymllooks 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.
