Допустим, у нас есть два приложения Rails (5/6):
- library_management_system (Rails 5)
- library_stats (Rails 6)
library_management_system имеет базу данных Postgres и, скажем, у нас есть:
- суперпользователь PG (супермен)
- пользователь PG только для чтения (кларк) (даже права на создание имеют был отозван)
library_stats имеет доступ только для чтения к базе данных library_management_system Postgres. Например, у library_stats database.yml
есть
development:
username: clark
Все в порядке в разработке. Так как нам никогда не нужно пересоздавать базу данных разработчика из library_stats.
Теперь я хотел бы проверить, что происходит с таким пользователем, доступным только для чтения, в моих тестах.
Я попытался просто использовать пользователь только для чтения:
test:
username: clark
К сожалению, это не оставляет рельсам достаточных прав для настройки БД (как вы можете видеть в конце поста). В идеале я хотел бы, чтобы настройка теста выполнялась с superman
, выполняющим взаимодействие с PG, а затем выполняла бы тесты с clark
, выполняющим взаимодействие.
Каков (в идеале не слишком сложный) способ, которым я могу это сделать?
В общем, любое решение, которое позволило бы правильно проверить, что происходит с пользователем PG только для чтения. , хорошо.
Трассировка:
29: from railties-6.0.2.1/lib/rails/test_help.rb:17:in `<main>'
28: from activerecord-6.0.2.1/lib/active_record/migration.rb:615:in `maintain_test_schema!'
27: from activerecord-6.0.2.1/lib/active_record/migration.rb:620:in `method_missing'
26: from activerecord-6.0.2.1/lib/active_record/migration.rb:867:in `suppress_messages'
25: from activerecord-6.0.2.1/lib/active_record/migration.rb:615:in `block in maintain_test_schema!'
24: from activerecord-6.0.2.1/lib/active_record/migration.rb:594:in `load_schema_if_pending!'
23: from activerecord-6.0.2.1/lib/active_record/migration.rb:594:in `all?'
22: from activerecord-6.0.2.1/lib/active_record/migration.rb:595:in `block in load_schema_if_pending!'
21: from activerecord-6.0.2.1/lib/active_record/tasks/database_tasks.rb:348:in `schema_up_to_date?'
20: from activerecord-6.0.2.1/lib/active_record/internal_metadata.rb:28:in `[]'
19: from activerecord-6.0.2.1/lib/active_record/relation/calculations.rb:193:in `pluck'
18: from activerecord-6.0.2.1/lib/active_record/relation.rb:828:in `skip_query_cache_if_necessary'
17: from activerecord-6.0.2.1/lib/active_record/relation/calculations.rb:193:in `block in pluck'
16: from activerecord-6.0.2.1/lib/active_record/connection_adapters/abstract/query_cache.rb:107:in `select_all'
15: from activerecord-6.0.2.1/lib/active_record/connection_adapters/abstract/database_statements.rb:70:in `select_all'
14: from activerecord-6.0.2.1/lib/active_record/connection_adapters/abstract/database_statements.rb:487:in `select'
13: from activerecord-6.0.2.1/lib/active_record/connection_adapters/postgresql/database_statements.rb:98:in `exec_query'
12: from activerecord-6.0.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:651:in `execute_and_clear'
11: from activerecord-6.0.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:670:in `exec_no_cache'
10: from activerecord-6.0.2.1/lib/active_record/connection_adapters/abstract_adapter.rb:708:in `log'
9: from activesupport-6.0.2.1/lib/active_support/notifications/instrumenter.rb:24:in `instrument'
8: from activerecord-6.0.2.1/lib/active_record/connection_adapters/abstract_adapter.rb:717:in `block in log'
7: from activerecord-6.0.2.1/lib/active_record/connection_adapters/abstract_adapter.rb:717:in `synchronize'
6: from activerecord-6.0.2.1/lib/active_record/connection_adapters/abstract_adapter.rb:718:in `block (2 levels) in log'
5: from activerecord-6.0.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:671:in `block in exec_no_cache'
4: from activesupport-6.0.2.1/lib/active_support/dependencies/interlock.rb:47:in `permit_concurrent_loads'
3: from activesupport-6.0.2.1/lib/active_support/concurrency/share_lock.rb:187:in `yield_shares'
2: from activesupport-6.0.2.1/lib/active_support/dependencies/interlock.rb:48:in `block in permit_concurrent_loads'
1: from activerecord-6.0.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:672:in `block (2 levels) in exec_no_cache'
activerecord-6.0.2.1/lib/active_record/connection_adapters/postgresql_adapter.rb:672:in `exec_params': ERROR: permission denied for relation ar_internal_metadata (PG::InsufficientPrivilege)
РЕДАКТИРОВАТЬ: я пошел со следующим решением
class LibraryManagementRecord < ApplicationRecord
self.abstract_class = true
if (Rails.env.test?)
ActiveRecord::Base.establish_connection(:lms_test)
end
end
и с двумя подключениями:
# database.yml
test:
username: superman
lms test:
username: clark
Теперь у нас ожидаемое поведение:
require 'test_helper'
class BookTest < ActiveSupport::TestCase
test 'cannot create book' do
error = assert_raises ActiveRecord::StatementInvalid do
Book.create!
end
assert_equal(
'PG::InsufficientPrivilege: ERROR: permission denied for relation books',
error.message.strip
)
end
end
Но оказывается, что есть еще одно ограничение: а именно, как вы вставляете, скажем, приборы. Вам, вероятно, придется явно получить соединение с разрешенной для записи ролью, чтобы вставить их.