Я впервые использую специальное промежуточное программное обеспечение, чтобы нормализовать обработку ошибок. У меня есть промежуточное программное обеспечение, определенное в app/middleware/error_handler.rb
и используемое в моем основном приложении.rb.
...
require_relative "../app/middleware/error_handler"
module AppName
class Application < Rails::Application
...
config.middleware.use Middleware::ErrorHandler
...
end
end
Все это отлично работает в тестах и разработке при маршрутизации на локальный хост. Но когда я нажимаю на github и действие берет верх, я получаю это после того, как он выполнит миграцию.
An error occurred while loading spec_helper.
Failure/Error: require_relative "../config/environment"
NameError:
uninitialized constant ErrorHandler
# ./config/environment.rb:5:in `<top (required)>'
# ./spec/rails_helper.rb:6:in `require_relative'
# ./spec/rails_helper.rb:6:in `<top (required)>'
# ./spec/spec_helper.rb:3:in `<top (required)>'
No examples found.
Вот мое действие/рабочий процесс
name: Run RSpec
on:
push:
branches:
- "*" # Trigger on push to any branch
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16.1
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${{ secrets.ROUTE_RATER_DATABASE_PASSWORD }}
POSTGRES_DB: postgres
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
redis:
image: redis
ports:
- 6379:6379
options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: "3.3.0"
- name: Install dependencies
run: |
gem install bundler
bundle install --jobs 4 --retry 3
- name: Setup DB, Run tests
env:
PGHOST: localhost
PGUSER: postgres
PGPORT: ${{ job.services.postgres.ports[5432] }}
PGPASSWORD: ${{ secrets.DATABASE_PASSWORD }}
REDIS_URL: redis://localhost:6379/1
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
RAILS_ENV: test
run: |
bin/rails db:create db:migrate db:schema:load
bundle exec rspec
Я просто переместил его в lib/middleware и изменил всю загрузку, которая у меня была, и это сработало :shrug: :laughcry: Zeitwerk и путь загрузки - моя ахиллесова пята банкомата :P Мне определенно есть еще что почитать. Спасибо!
Честно говоря, lib в любом случае там, где ему место. Рад, что вы разобрались.
Я так и думал, но я впервые делаю что-то подобное, и в учебниках, которые я видел, это было в приложении/промежуточном программном обеспечении. :(
Ожидается, что app/middleware/error_handler.rb
будет определять ErrorHandler
, но вы определяете пространство имен Middleware::ErrorHandler
.
Обычно, если бы вы запросили ErrorHandler
, он был бы загружен из первого error_handler.rb
файла, найденного в любом из корневых каталогов , в данном случае это app/middleware/
. Структура файла должна соответствовать именам модулей/классов относительно корневого каталога:
# app/middleware/error_handler.rb
# ^^^^^^^^^^^^^
# |
class ErrorHandler # >-'
end
Rails автоматически настраивает каталоги непосредственно под app/
как корневые. Благодаря этому вы можете просто загрузить ErrorHandler
, не требуя этого:
>> ErrorHandler
=> ErrorHandler
Если бы вы использовали пространство имен:
# app/middleware/error_handler.rb
module Middleware
class ErrorHandler
end
end
Вы получаете ошибку:
>> ErrorHandler
(irb):1:in `<main>': uninitialized constant ErrorHandler (NameError)
ErrorHandler
^^^^^^^^^^^^
Именно это и делает zeitwerk
, загружая ваше приложение в рабочую или тестовую среду ci:
# config/environments/test.rb
config.eager_load = ENV["CI"].present?
В процессе разработки вы можете дважды проверить, что ваше приложение может быть быстро загружено:
$ bin/rails zeitwerk:check
Hold on, I am eager loading the application.
expected file app/middleware/error_handler.rb to define constant ErrorHandler, but didn't
Поскольку вы не можете автоматически загружать перезагружаемый код во время загрузки в любом случае вам придется require
и использовать Middleware::ErrorHandler
, просто не помещайте его в путь autoload.
Вы также можете использовать autoload_once_paths или autoload_lib_once, которые автоматически загружают неперезагружаемый код, но вам придется переместить config.middleware.use
в инициализатор:
# config/application.rb
config.autoload_lib_once(ignore: %w(assets tasks))
# config/initializers/middleware.rb
Rails.application.config.middleware.use Middleware::ErrorHandler
# lib/middleware/error_handler.rb
module Middleware
class ErrorHandler
# ...
end
end
Этот ответ необычен.
Возможно, проблема с zietwerk, который ожидает, что структура каталогов для
Middleware::ErrorHandler
будет «app/middleware/middleware/error_handler», поскольку верхняя структура папок не считается частью вложенности модулей. Однако странно, что сама ссылка «неинициализированная константа ErrorHandler» не находится в пространстве имен.