在 Rails 应用程序的其他数据库中创建数据

Posted

技术标签:

【中文标题】在 Rails 应用程序的其他数据库中创建数据【英文标题】:Create data in additional databases in Rails application 【发布时间】:2022-01-06 16:35:51 【问题描述】:

在我的 rails(版本 6.1.3.2)应用程序中,我有 2 个数据库:

    主要,适用于大多数型号 api_logs,用于ApiLog 模型 我的database.yml 看起来像:
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

我的ApiLog 模型有以下迁移:

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

数据库已成功创建和迁移。 在我的app/models/api_log.rb 我有以下声明:

# 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

有了这个,我可以运行如下读取查询:

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

他们很好。

但是当我尝试创建一个时:

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.)

我了解错误是由于模型中的声明而抱怨这是一个抽象类。但是,如果我删除self.abstract_class=true,即使ApiLog.count 也不再起作用:

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)

我已关注Rails guide,但它似乎无法正常工作,即使读取查询正常。

那么如何在新数据库中创建api_logs 对象呢?

谢谢!

【问题讨论】:

【参考方案1】:

来自 Rails 指南:

你的问题是你试图让一个类既作为你的模型又作为指南所说的连接模型。

重要的是在单个模型中连接到您的数据库,然后 从该模型继承表而不是连接多个 单个模型到同一个数据库。

我相信你只需要将你拥有的东西分成两个模型:

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

读取查询似乎以您的方式工作的唯一原因是您没有任何匹配的记录,因此结果是nil。如果存在现有记录,您将收到与创建相同的错误,因为此问题与 SQL 查询无关,而与生成的类实例化有关。

【讨论】:

以上是关于在 Rails 应用程序的其他数据库中创建数据的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有 XML(仅限 HTML)的 Rails 中创建脚手架?

Rails:在父模型的视图中创建一个 has_one 模型?

如何编写 Rake 任务以将数据导入 Rails 应用程序?

当我引用其他表时,如何保存在 Access 2003 中的表单中创建的数据?

根据其他列值/ Pandas -Python 在数据框中创建 ID 列

带有可以表示多种数据类型的列的 Rails 模型