Fail to setup database_cleaner for dual database
还没有人认领这个 Issue。
评估
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 新手友好度
- 35/100
调研方向
从 lib/database_cleaner/active_record/base.rb 开始,重点查看 connection_class、lookup_from_connection_pool 和 establish_connection。使用 test 和 secondary_test 连接重现两次 DatabaseCleaner 启动,然后添加回归测试覆盖,证明 Device 和 User 会保留正确的连接,同时 ActiveRecord::Base.establish_connection 不会影响所有后代类。
由索引模型根据 Issue 内容生成。
描述
I have two database, one with a model call Device, and the other has a model call User.
When I set up database_cleaner according to readme describe:
config.use_transactional_fixtures = false
config.before(:suite) do
DatabaseCleaner[:active_record,{:connection => :test}].strategy = :transaction
DatabaseCleaner[:active_record,{:connection => :secondary_test}].strategy = :transaction
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
I found that in my test, device model's connection will point to secondary_test database. And I will have following error as my secondary_test database don't have a table call devices:
ActiveRecord::StatementInvalid:
PG::UndefinedTable: ERROR: relation "devices" does not exist
LINE 5: WHERE a.attrelid = '"devices"'::regclass
^
: SELECT a.attname, format_type(a.atttypid, a.atttypmod),
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod
FROM pg_attribute a LEFT JOIN pg_attrdef d
ON a.attrelid = d.adrelid AND a.attnum = d.adnum
WHERE a.attrelid = '"devices"'::regclass
AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY a.attnum
I dig in the code, and found that it is cause by #connection_class
def connection_class
@connection_class ||= if db && !db.is_a?(Symbol)
db
elsif connection_hash
lookup_from_connection_pool || establish_connection
else
::ActiveRecord::Base
end
end
private
def lookup_from_connection_pool
if ::ActiveRecord::Base.respond_to?(:descendants)
database_name = connection_hash["database"] || connection_hash[:database]
models = ::ActiveRecord::Base.descendants
models.detect { |m| m.connection_pool.spec.config[:database] == database_name }
end
end
def establish_connection
::ActiveRecord::Base.establish_connection(connection_hash)
end
However, since ::ActiveRecord::Base.descendants is blank when lookup_from_connection_pool is called, lookup_from_connection_pool would return nil, and establish_connection will be called. Unfortunately, ActiveRecord::Base.establish_connection(connection_hash) has a huge side effect in Rails 4+. It will set connection to specify one for ALL models that inherit from ActiveRecord::Base class. This can be reproduced by following code:
ActiveRecord::Base.establish_connection('test')
Device.connection
In my case, following code:
DatabaseCleaner[:active_record,{:connection => :test}].start
DatabaseCleaner[:active_record,{:connection => :secondary_test}].start
will first set ALL ActiveRecord::Base descendants' connections to test db, then it will set ALL their connection to secondary_test. Therefore, when I try to use Device in my spec, I will have PG::UndefinedTable: ERROR
Here is the similar issues that cause by the side effect for establish_connection:
- 主要语言
- Ruby
- 星标
- 3k
- 派生
- 483
- PR 合并指标
- 30 天内没有已合并 PR
环境准备
- 提供 Dockerfile 或 Docker Compose 文件
- 没有 Pull Request 模板
- 没有贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
DatabaseCleaner/database_cleaner 的其他 Issue
-
难度 3/5 1-2 天 新手友好度 67/100
-
难度 4/5 3-5 天 新手友好度 25/100
-
难度 3/5 1-2 天 新手友好度 45/100
-
难度 4/5 3-5 天 新手友好度 35/100
DatabaseCleaner/database_cleaner#717 · 5 条评论 · 1 个 reaction ·
-
难度 4/5 3-5 天 新手友好度 25/100
DatabaseCleaner/database_cleaner#716 · 2 条评论 ·
查看 DatabaseCleaner/database_cleaner 的全部 Issue
相似的 Issue
-
bug
难度 2/5 1-3 小时 新手友好度 82/100
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 75/100
GantMan/jail-monkey#380 ·
-
难度 2/5 1-3 小时 新手友好度 62/100
voxpupuli/puppet-wireguard#151 ·
-
bug
难度 2/5 1-3 小时 新手友好度 72/100
维护者通常 1 天内回复
-
Search accepts any value for `requests_per_page` and `per_page`可能已有人在做 关联的 PR 仍在进行中或已合并。 未关闭bug f:search
难度 2/5 1-3 小时 新手友好度 78/100
维护者通常 1 天内回复