You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails 7中解除GET请求数据库readonly模式适配RailsMiniProfiler

RailsMiniProfiler在GET请求下无法写入数据库的解决方案

我清楚GET请求写入数据库不符合RESTful设计,但正在为基于Rails 7.0.3.1、MySQL 5.7(使用activerecord-pedantmysql2-adapter适配器)的项目部署RailsMiniProfiler。这个工具在开发环境中很实用,但除GET请求外其他请求都能正常运行——原因是该Gem尝试将分析信息写入rmp_profiled_request表,但Rails在GET请求下处于只读模式,报错如下:

E, [2024-05-29T14:32:10.392477 #58380] ERROR -- : [RailsMiniProfiler] Could not save profile: Write query attempted while in readonly mode: INSERT INTO `rmp_profiled_request` 

问题

  • 是否可以为rmp_profiled_request表永久授予写入权限?
  • readonly模式的逻辑在哪里可以覆盖?
  • 是否可以在database.yml中配置特殊参数?

注:仅在开发环境使用RailsMiniProfiler,所有修改仅针对开发环境生效,目前查阅官方文档未找到相关解决方法。

技术细节

  • Rails版本:7.0.3.1
  • Ruby版本:ruby 3.1.4p223 (2023-03-30 revision 957bb7cb81) [x86_64-linux]
  • 数据库:MySQL 5.7,使用pedant_mysql2适配器

config/database.yml

defaults: &defaults
  adapter:         pedant_mysql2
  username:        <%= ENV['MY_API_DATABASE_USERNAME'] %>
  password:        <%= ENV['MY_API_DATABASE_PASSWORD'] %>
  encoding:        utf8
  collation:       utf8_unicode_ci
  pool:            <%= ENV["DB_POOL"] %>
  timeout:         5000
  automatic_close: false

deployment_defaults: &deployment_defaults
  sslca:                 "/etc/ssl/certs/mysql-ssl-ca-cert.pem"
  init_command:          "SET optimizer_switch='hash_join=off'"
  variables:
   group_concat_max_len: 15000

primary_defaults: &primary_defaults
    host:     <%= ENV['MY_API_PRIMARY_DATABASE_HOST'] %>
    database: <%= ENV['MY_API_DATABASE_NAME'] %>

primary_replica_defaults: &primary_replica_defaults
    host:     <%= ENV['MY_API_PRIMARY_REPLICA_DATABASE_HOST'] %>
    database: <%= ENV['MY_API_DATABASE_NAME'] %>
    replica:  true

dw_defaults: &dw_defaults
    host:             <%= ENV['MY_DW_DATABASE_HOST'] %>
    database:         <%= ENV['MY_DW_DATABASE_NAME'] %>
    migrations_paths: db/migrate-dw

dw_replica_defaults: &dw_replica_defaults
    host:     <%= ENV['MY_DW_REPLICA_DATABASE_HOST'] %>
    database: <%= ENV['MY_DW_DATABASE_NAME'] %>
    replica:  true

development:
  primary:
    <<: *defaults
    <<: *primary_defaults
  primary_replica:
    <<: *defaults
    <<: *primary_replica_defaults
  dw:
    <<: *defaults
    <<: *dw_defaults
  dw_replica:
    <<: *defaults
    <<: *dw_replica_defaults

test:
  primary:
    <<: *defaults
    host:     <%= ENV['MY_API_PRIMARY_DATABASE_HOST'] %>
    database: my-api-test<%= ENV['TEST_ENV_NUMBER'] %>
  primary_replica:
    <<: *defaults
    host:     <%= ENV['MY_API_PRIMARY_REPLICA_DATABASE_HOST'] %>
    database: my-api-test<%= ENV['TEST_ENV_NUMBER'] %>
    replica: true
  dw:
    <<: *defaults
    host:             <%= ENV['MY_DW_DATABASE_HOST'] %>
    database:         my-dw-test<%= ENV['TEST_ENV_NUMBER'] %>
    migrations_paths: db/dw_migrate
  dw_replica:
    <<: *defaults
    host:     <%= ENV['MY_DW_REPLICA_DATABASE_HOST'] %>
    database: my-dw-test<%= ENV['TEST_ENV_NUMBER'] %>
    replica:  true

qa:
  primary:
    <<: *defaults
    <<: *deployment_defaults
    <<: *primary_defaults
  primary_replica:
    <<: *defaults
    <<: *deployment_defaults
    <<: *primary_replica_defaults
  dw:
    <<: *defaults
    <<: *deployment_defaults
    <<: *dw_defaults
  dw_replica:
    <<: *defaults
    <<: *deployment_defaults
    <<: *dw_replica_defaults

staging:
  primary:
    <<: *defaults
    <<: *deployment_defaults
    <<: *primary_defaults
  primary_replica:
    <<: *defaults
    <<: *deployment_defaults
    <<: *primary_replica_defaults
  dw:
    <<: *defaults
    <<: *deployment_defaults
    <<: *dw_defaults
  dw_replica:
    <<: *defaults
    <<: *deployment_defaults
    <<: *dw_replica_defaults

integration:
  primary:
    <<: *defaults
    <<: *deployment_defaults
    <<: *primary_defaults
  primary_replica:
    <<: *defaults
    <<: *deployment_defaults
    <<: *primary_replica_defaults
  dw:
    <<: *defaults
    <<: *deployment_defaults
    <<: *dw_defaults
  dw_replica:
    <<: *defaults
    <<: *deployment_defaults
    <<: *dw_replica_defaults

production:
  primary:
    <<: *defaults
    <<: *deployment_defaults
    <<: *primary_defaults
  primary_replica:
    <<: *defaults
    <<: *deployment_defaults
    <<: *primary_replica_defaults
  dw:
    <<: *defaults
    <<: *deployment_defaults
    <<: *dw_defaults
  dw_replica:
    <<: *defaults
    <<: *deployment_defaults
    <<: *dw_replica_defaults

ci:
  primary:
    <<: *defaults
    <<: *primary_defaults
  primary_replica:
    <<: *defaults
    <<: *primary_replica_defaults
  dw:
    <<: *defaults
    <<: *dw_defaults
  dw_replica:
    <<: *defaults
    <<: *dw_replica_defaults

demo:
  primary:
    <<: *defaults
    adapter:  mysql2
    host:     <%= ENV['MY_API_PRIMARY_DATABASE_HOST'] %>
    database: my-api-demo
  primary_replica:
    <<: *defaults
    adapter:  mysql2
    host:     <%= ENV['MY_API_PRIMARY_REPLICA_DATABASE_HOST'] %>
    database: my-api-demo
    replica:  true
  dw:
    <<: *defaults
    adapter:          mysql2
    host:             <%= ENV['MY_DW_DATABASE_HOST'] %>
    database:         my-dw-demo
    migrations_paths: db/migrate-dw
  dw_replica:
    <<: *defaults
    adapter:  mysql2
    host:     <%= ENV['MY_DW_REPLICA_DATABASE_HOST'] %>
    database: my-dw-demo
    replica:  true

解决方案

1. 关于为rmp_profiled_request表永久授予写入权限

这不是表权限问题——你的开发环境配置了主从分离,GET请求默认路由到只读副本,而副本库本身是只读的,所以不管表权限如何,都无法写入。核心是要让RailsMiniProfiler的写入操作强制走主库。

2. 覆盖readonly模式逻辑的方法

最直接的方式是修改RailsMiniProfiler的模型,让它始终使用主库连接。在开发环境下创建一个初始化文件config/initializers/rails_mini_profiler.rb:

if Rails.env.development?
  RailsMiniProfiler::ProfiledRequest.class_eval do
    def save(*)
      ActiveRecord::Base.connected_to(role: :writing) do
        super
      end
    end

    def save!(*)
      ActiveRecord::Base.connected_to(role: :writing) do
        super
      end
    end
  end
end

这样每次保存分析数据时,都会强制切换到主库(可写连接),绕过GET请求的只读限制。

3. database.yml中的配置调整

如果开发环境不需要主从分离,直接简化配置,去掉replica节点:

development:
  primary:
    <<: *defaults
    <<: *primary_defaults
  dw:
    <<: *defaults
    <<: *dw_defaults

这样所有请求都会走主库,自然可以写入。但如果需要保留主从配置,优先使用上面的模型修改方法。

内容的提问来源于stack exchange,提问作者Oscar Ortiz García

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 10:24:59