【GitHub Actions·Rails】NoMethodError: Cannot load database configuration: undefined method `[]' for nil:NilClass

0. 문제


rails db:create 또는 rails db:migrate가 도중에 실패합니다.
에러 로그는 이하와 같은, 조금 뿌리깊은 것 같은 느낌.
$ bundle exec rake db:create
rake aborted!
NoMethodError: Cannot load database configuration:
undefined method `[]' for nil:NilClass
(erb):20:in `<main>'
hoge/fuga/app/models/application_record.rb:1:in `<main>'
...
/opt/hostedtoolcache/Ruby/2.7.2/x64/bin/bundle:23:in `load'
/opt/hostedtoolcache/Ruby/2.7.2/x64/bin/bundle:23:in `<main>'
Tasks: TOP => db:create => db:load_config => environment
(See full trace by running task with --trace)
Error: Process completed with exit code 1.

application_record.rb의 첫 번째 줄에서 발생했기 때문에 어떤 일인지,

1. 원인



여기 근처를 참고.
  • 여러 번 해도 Nill class, 원인 불명의 migrate faild, 문제는 credentials.yml.enc가 붙잡고 있었다.
  • 【Rails】rails s를 실행하면 「Cannot load database configuration」라고 에러가 나와 강제 종료된다
  • cannot load 'rails.application.database_configuration' undefined method'[]' for nil:NilClass

  • 요점은, 예를 들면 이하의 경우,
    <%= Rails.application.credentials.database[:host] %>
    

    와 같이 credentials.yml.enc의 비밀 정보를 호출하는 설명에서,Rails.application.credentials.database가 비어 있기 때문에,[:host] 가 호출되지 않고,undefined method '[]' for nil:NilClass가 발생합니다.
    Rails.application.credentials.database가 비어 버리는 것은 환경 의존의 문제로,
    GitHub Actions의 Ubuntu 가상 환경이기 때문에 credentials.yml.enc를 볼 수 없습니다.
    GitHub Actions 측에서 은닉 정보를 설정해야 했기 때문입니다.

    2. 솔루션



    이 예제에서는 config/database.yml에 정의되었습니다.Rails.application.credentials.database[:host]를 부를 수 있거나 부르지 않으면 좋다.

    다음 중 하나를 적용하면 통과하게 된다.

    솔루션 1. GitHub 리포지토리에서 RAILS_MASTER_KEY 설정



    GitHub Actions를 설정하는 GitHub 리포지토리에서Settings > Secrets 에서 리포지토리에 은닉 정보를 설정할 수 있습니다.


    config/master.key 의 값을 입력합니다 (줄 바꿈이나 공백을 포함하면 작동하지 않을 수 있습니다).





    위에서 설정한 비밀 정보는 ${{ secrets.設定した名前 }} 로 GitHub Actions 설정 파일에서 호출할 수 있습니다.
    # 例
    ...
        - name: Run tests
          env:
            RAILS_ENV: test
            RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
          run: bundle exec rspec
    ...
    

    이렇게하면 GitHub Actions 환경에서 Rails.application.credentials를 볼 수 있습니다.

    참고


  • GitHub Action에서 Docker 컨테이너를 빌드하고 Amazon ECR에 저장

  • 해결 방법 2. database.yml.ci 만들기 및 사용


    # .github/workflows/ruby.yml
    ...
        - name: Setup test database
          env:
            RAILS_ENV: test
          run: |
            cp config/database.yml.ci config/database.yml
            bundle exec rake db:create
            bundle exec rake db:migrate
    ...
    
    # config/database.yml.ci
    default: &default
      adapter: mysql2
      encoding: utf8mb4
      charset: utf8mb4
      collation: utf8mb4_general_ci
      pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
      host: 127.0.0.1
      port: 3306
      username: root
      password:
    
    test:
      <<: *default
      database: sample_app_test
    
    

    해결 방법 3. Rails.application.credentials.hoge[:fuga]를 호출하지 않음



    yml 파일에서도 if문을 쓸 수 있다.
    # config/database.yml
    ...
    production:
      <<: *default
      <% if Rails.application.credentials.database.present? %>
        database: sample_app_production
        host: <%= Rails.application.credentials.database[:host] %>
        username: <%= Rails.application.credentials.database[:username] %>
        password: <%= Rails.application.credentials.database[:password] %>
      <% end %>
    
    <% if Rails.env.production? %> 하지만 좋을지도.

    3. GitHub Actions 설정 파일



    일단 이런 느낌이 들었습니다.
    # This workflow uses actions that are not certified by GitHub.
    # They are provided by a third-party and are governed by
    # separate terms of service, privacy policy, and support
    # documentation.
    # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
    # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
    
    name: Rails Tests
    
    on: push
    
    jobs:
      test:
        runs-on: ubuntu-latest
    
        services:
          mysql:
            image: mysql:5.7
            env:
              MYSQL_USER: root
              MYSQL_ALLOW_EMPTY_PASSWORD: yes
              BIND-ADDRESS: 0.0.0.0
            ports:
            - 3306:3306
            options: >-
              --health-cmd "mysqladmin ping -h localhost"
              --health-interval 20s
              --health-timeout 10s
              --health-retries 10
    
        steps:
        - name: Checkout code
          uses: actions/checkout@v2
    
        - name: Set up Ruby 2.7
          uses: actions/setup-ruby@v1
          with:
            ruby-version: 2.7
    
        - name: Cache gems
          uses: actions/cache@preview
          with:
            path: vendor/bundle
            key: ${{ runner.os }}-gem-${{ hashFiles('**/Gemfile.lock') }}
            restore-keys: |
              ${{ runner.os }}-gem-
    
        - name: Cache node modules
          uses: actions/cache@preview
          with:
            path: node_modules
            key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}
            restore-keys: |
              ${{ runner.os }}-node-
    
        - name: bundle install
          run: |
            gem install bundler
            bundle install --jobs 4 --retry 3 --path vendor/bundle
    
        - name: yarn install
          run:  yarn install --check-files
    
        - name: Setup test database
          env:
            RAILS_ENV: test
          run: |
            cp config/database.yml.ci config/database.yml
            bundle exec rake db:setup
    
        - name: Run Lint
          run: bundle exec rubocop
    
        - name: Run tests
          env:
            RAILS_ENV: test
            RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
          run: bundle exec rspec
    
    

    도움이되면 다행입니다.

    좋은 웹페이지 즐겨찾기