Project

General

Profile

bundle exec rake db:migrate RAILS_ENV=production -> NoMethodError: undefined method `stringify_keys' for nil:NilClass (NoMethodError)

Added by David Gessel 3 months ago

Environment

redmine51-5.1.3_2
FreeBSD 14.1-RELEASE-p3 GENERIC amd64
ruby-3.2.5,1
rubygem-rails61-6.1.7.8
mariadb105-server-10.5.16
Environment production

It seems "about" can be executed as:
  1. bundle exec rake about RAILS_ENV=production
About your application's environment
Rails version      6.1.7.8
Ruby version       ruby 3.2.5 (2024-07-26 revision 31d0f1a2e7) [amd64-freebsd14]
RubyGems version   3.5.18
Rack version       2.2.9
Middleware         ActionDispatch::HostAuthorization, Rack::ContentLength, Rack::Sendfile, ActionDispatch::Static, ActionDispatch::Executor, ActiveSupport::Cache::Strategy::LocalCache::Middleware, Rack::Runtime, Rack::MethodOverride, ActionDispatch::RequestId, RequestStore::Middleware, ActionDispatch::RemoteIp, Rails::Rack::Logger, ActionDispatch::ShowExceptions, ActionDispatch::DebugExceptions, ActionDispatch::ActionableExceptions, ActionDispatch::Callbacks, ActionDispatch::Cookies, ActionDispatch::Session::CookieStore, ActionDispatch::Flash, ActionDispatch::ContentSecurityPolicy::Middleware, ActionDispatch::PermissionsPolicy::Middleware, Rack::Head, Rack::ConditionalGet, Rack::ETag, Rack::TempfileReaper
Application root   /usr/local/www/redmine
Environment        production

Errors

Attempting to upgrade to current, I get stopped by an error that I'm not finding much help from search for:

$ bundle exec rake db:migrate RAILS_ENV=production
WARNING: Nokogiri was built against libxml version 2.11.8, but has dynamically loaded 2.11.9
rake aborted!
NoMethodError: undefined method `stringify_keys' for nil:NilClass (NoMethodError)

          variables = @config.fetch(:variables, {}).stringify_keys
                                                   ^^^^^^^^^^^^^^^
/usr/local/bin/bundle:25:in `load'
/usr/local/bin/bundle:25:in `<main>'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)

I can run with --trace if that's helpful.


Replies (8)

RE: bundle exec rake db:migrate RAILS_ENV=production -> NoMethodError: undefined method `stringify_keys' for nil:NilClass (NoMethodError) - Added by David Gessel 3 months ago

I forgot to mention, this is an update from redmine42-4.2.5 with a clean install, just moved database.yml, settings.yml, and /files to the new folder, no plugins migrated yet.

RE: bundle exec rake db:migrate RAILS_ENV=production -> NoMethodError: undefined method `stringify_keys' for nil:NilClass (NoMethodError) - Added by Holger Just 3 months ago

The code quoted in the error message is not part of Redmine 5.1.3. You can get more information by appending --trace to your command. Depending on the source of your Redmine code, someone may have adapted it.

In any case, note that the config/settings.yml file is specific to the respective Redmine version and you must not edit or replace it with an old version. See RedmineUpgrade for complete upgrade instructions.

RE: bundle exec rake db:migrate RAILS_ENV=production -> NoMethodError: undefined method `stringify_keys' for nil:NilClass (NoMethodError) - Added by David Gessel 3 months ago

Thanks for the help!

The source is https://www.freshports.org/www/redmine51/

Code for the FreeBSD port is https://github.com/freebsd/freebsd-ports/tree/main/www/redmine51

A few files are patched for FreeBSD.

To test in isolation, I did a completely new install, fresh database, no modifications to configuration.yml and only the database.yml settings to connect to the new database (noting that MariaDB throws an error with either the transaction_isolation or the tx_isolation variable set. The only modifications to the as-shipped /redmine folder are the following database.yml configurations:

# Default setup is given for MySQL 5.7.7 or later.
# Examples for PostgreSQL, SQLite3 and SQL Server can be found at the end.
# Line indentation must be 2 spaces (no tabs).

production:
  adapter: mysql2
  database: redmine5t
  host: 10.3.69.183
  username: redmine5t
  password: "randompassword" 
  # Use "utf8" instead of "utfmb4" for MySQL prior to 5.7.7
  encoding: utf8mb4
  variables:
    # Recommended `transaction_isolation` for MySQL to avoid concurrency issues is
    # `READ-COMMITTED`.
    # In case of MySQL lower than 8, the variable name is `tx_isolation`.
    # See https://www.redmine.org/projects/redmine/wiki/MySQL_configuration
    # should be updated to "transaction_isolation" after db update (then test)
    # transaction_isolation: "tx_isolation" 

development:
  adapter: mysql2
  database: redmine_development
  host: localhost
  username: root
  password: "" 
  # Use "utf8" instead of "utfmb4" for MySQL prior to 5.7.7
  encoding: utf8mb4
  variables:
    transaction_isolation: "READ-COMMITTED" 

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  adapter: mysql2
  database: redmine_test
  host: localhost
  username: root
  password: "" 
  # Use "utf8" instead of "utfmb4" for MySQL prior to 5.7.7
  encoding: utf8mb4
  variables:
    transaction_isolation: "READ-COMMITTED" 

Then the following command sequence yields:

$ whoami
redmine
$ bundle config set --local without 'development test'
You are replacing the current local value of without, which is currently "development:test" 
$ bundle install
Bundle complete! 30 Gemfile dependencies, 75 gems now installed.
Gems in the groups 'development' and 'test' were not installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
$ RAILS_ENV=production bundle exec rake db:migrate --trace
** Invoke db:migrate (first_time)
** Invoke db:load_config (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute db:load_config
** Execute db:migrate
rake aborted!
NoMethodError: undefined method `stringify_keys' for nil:NilClass (NoMethodError)

          variables = @config.fetch(:variables, {}).stringify_keys
                                                   ^^^^^^^^^^^^^^^
/usr/local/lib/ruby/gems/3.2/gems/activerecord-6.1.7.8/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:744:in `configure_connection'
/usr/local/lib/ruby/gems/3.2/gems/activerecord-6.1.7.8/lib/active_record/connection_adapters/mysql2_adapter.rb:144:in `configure_connection'
/usr/local/lib/ruby/gems/3.2/gems/activerecord-6.1.7.8/lib/active_record/connection_adapters/mysql2_adapter.rb:53:in `initialize'
/usr/local/lib/ruby/gems/3.2/gems/activerecord-6.1.7.8/lib/active_record/connection_adapters/mysql2_adapter.rb:22:in `new'
/usr/local/lib/ruby/gems/3.2/gems/activerecord-6.1.7.8/lib/active_record/connection_adapters/mysql2_adapter.rb:22:in `mysql2_connection'
/usr/local/lib/ruby/gems/3.2/gems/activerecord-6.1.7.8/lib/active_record/connection_adapters/abstract/connection_pool.rb:882:in `public_send'
/usr/local/lib/ruby/gems/3.2/gems/activerecord-6.1.7.8/lib/active_record/connection_adapters/abstract/connection_pool.rb:882:in `new_connection'
/usr/local/lib/ruby/gems/3.2/gems/activerecord-6.1.7.8/lib/active_record/connection_adapters/abstract/connection_pool.rb:926:in `checkout_new_connection'
/usr/local/lib/ruby/gems/3.2/gems/activerecord-6.1.7.8/lib/active_record/connection_adapters/abstract/connection_pool.rb:905:in `try_to_checkout_new_connection'
/usr/local/lib/ruby/gems/3.2/gems/activerecord-6.1.7.8/lib/active_record/connection_adapters/abstract/connection_pool.rb:866:in `acquire_connection'
/usr/local/lib/ruby/gems/3.2/gems/activerecord-6.1.7.8/lib/active_record/connection_adapters/abstract/connection_pool.rb:588:in `checkout'
/usr/local/lib/ruby/gems/3.2/gems/activerecord-6.1.7.8/lib/active_record/connection_adapters/abstract/connection_pool.rb:428:in `connection'
/usr/local/lib/ruby/gems/3.2/gems/activerecord-6.1.7.8/lib/active_record/connection_adapters/abstract/connection_pool.rb:1128:in `retrieve_connection'
/usr/local/lib/ruby/gems/3.2/gems/activerecord-6.1.7.8/lib/active_record/connection_handling.rb:327:in `retrieve_connection'
/usr/local/lib/ruby/gems/3.2/gems/activerecord-6.1.7.8/lib/active_record/connection_handling.rb:283:in `connection'
/usr/local/lib/ruby/gems/3.2/gems/activerecord-6.1.7.8/lib/active_record/tasks/database_tasks.rb:237:in `migrate'
/usr/local/lib/ruby/gems/3.2/gems/activerecord-6.1.7.8/lib/active_record/railties/databases.rake:92:in `block (3 levels) in <top (required)>'
/usr/local/lib/ruby/gems/3.2/gems/activerecord-6.1.7.8/lib/active_record/railties/databases.rake:90:in `each'
/usr/local/lib/ruby/gems/3.2/gems/activerecord-6.1.7.8/lib/active_record/railties/databases.rake:90:in `block (2 levels) in <top (required)>'
/usr/local/lib/ruby/gems/3.2/gems/rake-13.2.1/lib/rake/task.rb:281:in `block in execute'
/usr/local/lib/ruby/gems/3.2/gems/rake-13.2.1/lib/rake/task.rb:281:in `each'
/usr/local/lib/ruby/gems/3.2/gems/rake-13.2.1/lib/rake/task.rb:281:in `execute'
/usr/local/lib/ruby/gems/3.2/gems/rake-13.2.1/lib/rake/task.rb:219:in `block in invoke_with_call_chain'
/usr/local/lib/ruby/gems/3.2/gems/rake-13.2.1/lib/rake/task.rb:199:in `synchronize'
/usr/local/lib/ruby/gems/3.2/gems/rake-13.2.1/lib/rake/task.rb:199:in `invoke_with_call_chain'
/usr/local/lib/ruby/gems/3.2/gems/rake-13.2.1/lib/rake/task.rb:188:in `invoke'
/usr/local/lib/ruby/gems/3.2/gems/rake-13.2.1/lib/rake/application.rb:188:in `invoke_task'
/usr/local/lib/ruby/gems/3.2/gems/rake-13.2.1/lib/rake/application.rb:138:in `block (2 levels) in top_level'
/usr/local/lib/ruby/gems/3.2/gems/rake-13.2.1/lib/rake/application.rb:138:in `each'
/usr/local/lib/ruby/gems/3.2/gems/rake-13.2.1/lib/rake/application.rb:138:in `block in top_level'
/usr/local/lib/ruby/gems/3.2/gems/rake-13.2.1/lib/rake/application.rb:147:in `run_with_threads'
/usr/local/lib/ruby/gems/3.2/gems/rake-13.2.1/lib/rake/application.rb:132:in `top_level'
/usr/local/lib/ruby/gems/3.2/gems/rake-13.2.1/lib/rake/application.rb:83:in `block in run'
/usr/local/lib/ruby/gems/3.2/gems/rake-13.2.1/lib/rake/application.rb:214:in `standard_exception_handling'
/usr/local/lib/ruby/gems/3.2/gems/rake-13.2.1/lib/rake/application.rb:80:in `run'
/usr/local/lib/ruby/gems/3.2/gems/rake-13.2.1/exe/rake:27:in `<top (required)>'
/usr/local/bin/rake:25:in `load'
/usr/local/bin/rake:25:in `<top (required)>'
/usr/local/lib/ruby/gems/3.2/gems/bundler-2.5.14/lib/bundler/cli/exec.rb:58:in `load'
/usr/local/lib/ruby/gems/3.2/gems/bundler-2.5.14/lib/bundler/cli/exec.rb:58:in `kernel_load'
/usr/local/lib/ruby/gems/3.2/gems/bundler-2.5.14/lib/bundler/cli/exec.rb:23:in `run'
/usr/local/lib/ruby/gems/3.2/gems/bundler-2.5.14/lib/bundler/cli.rb:455:in `exec'
/usr/local/lib/ruby/gems/3.2/gems/bundler-2.5.14/lib/bundler/vendor/thor/lib/thor/command.rb:28:in `run'
/usr/local/lib/ruby/gems/3.2/gems/bundler-2.5.14/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
/usr/local/lib/ruby/gems/3.2/gems/bundler-2.5.14/lib/bundler/vendor/thor/lib/thor.rb:527:in `dispatch'
/usr/local/lib/ruby/gems/3.2/gems/bundler-2.5.14/lib/bundler/cli.rb:35:in `dispatch'
/usr/local/lib/ruby/gems/3.2/gems/bundler-2.5.14/lib/bundler/vendor/thor/lib/thor/base.rb:584:in `start'
/usr/local/lib/ruby/gems/3.2/gems/bundler-2.5.14/lib/bundler/cli.rb:29:in `start'
/usr/local/lib/ruby/gems/3.2/gems/bundler-2.5.14/exe/bundle:28:in `block in <top (required)>'
/usr/local/lib/ruby/gems/3.2/gems/bundler-2.5.14/lib/bundler/friendly_errors.rb:117:in `with_friendly_errors'
/usr/local/lib/ruby/gems/3.2/gems/bundler-2.5.14/exe/bundle:20:in `<top (required)>'
/usr/local/bin/bundle:25:in `load'
/usr/local/bin/bundle:25:in `<main>'
Tasks: TOP => db:migrate

RE: bundle exec rake db:migrate RAILS_ENV=production -> NoMethodError: undefined method `stringify_keys' for nil:NilClass (NoMethodError) - Added by David Gessel 3 months ago

Also, poking a bit more:

/usr/local/www/redmine # grep -r "stringify_keys" *
app/models/query.rb:      json[field] = options.stringify_keys
app/models/project.rb:    initialized = (attributes || {}).stringify_keys
app/models/issue.rb:    attrs.stringify_keys!
lib/plugins/acts_as_customizable/lib/acts_as_customizable.rb:            v = v.stringify_keys
lib/plugins/acts_as_customizable/lib/acts_as_customizable.rb:          values = values.stringify_keys
lib/plugins/acts_as_attachable/lib/acts_as_attachable.rb:            attachments = attachments.stringify_keys
lib/redmine/configuration.rb:        settings.stringify_keys!

RE: bundle exec rake db:migrate RAILS_ENV=production -> NoMethodError: undefined method `stringify_keys' for nil:NilClass (NoMethodError) - Added by David Gessel 3 months ago

oops, here:

gems/3.2/gems/activerecord-4.2.11.3/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:        variables = @config.fetch(:variables, {}).stringify_keys

RE: bundle exec rake db:migrate RAILS_ENV=production -> NoMethodError: undefined method `stringify_keys' for nil:NilClass (NoMethodError) - Added by David Gessel 3 months ago

Cleaned up the gems files so the result is now:

# grep -r "variables, {}).stringify_keys" *
gems/3.2/gems/activerecord-6.1.7.8/lib/active_record/connection_adapters/postgresql_adapter.rb:          variables = @config.fetch(:variables, {}).stringify_keys
gems/3.2/gems/activerecord-6.1.7.8/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:          variables = @config.fetch(:variables, {}).stringify_keys

Since mysql is configured it is almost certainly the second that is throwing the error.

RE: bundle exec rake db:migrate RAILS_ENV=production -> NoMethodError: undefined method `stringify_keys' for nil:NilClass (NoMethodError) - Added by Holger Just 3 months ago

Okay, the cause of the error is Rails which reads your config/database.yml. In your file, you have defined an empty variables section within your production environment, which is thus parsed as `nil`. To fix this, when not setting any variables, you should comment out (or remove) the variables section entirely from your database.yml, e.g.:

# Default setup is given for MySQL 5.7.7 or later.
# Examples for PostgreSQL, SQLite3 and SQL Server can be found at the end.
# Line indentation must be 2 spaces (no tabs).

production:
  adapter: mysql2
  database: redmine5t
  host: 10.3.69.183
  username: redmine5t
  password: "randompassword" 
  # Use "utf8" instead of "utfmb4" for MySQL prior to 5.7.7
  encoding: utf8mb4
  # variables:
  #   # Recommended `transaction_isolation` for MySQL to avoid concurrency issues is
  #   # `READ-COMMITTED`.
  #   # In case of MySQL lower than 8, the variable name is `tx_isolation`.
  #   # See https://www.redmine.org/projects/redmine/wiki/MySQL_configuration
  #   # should be updated to "transaction_isolation" after db update (then test)
  #   transaction_isolation: "tx_isolation" 

development:
  adapter: mysql2
  database: redmine_development
  host: localhost
  username: root
  password: "" 
  # Use "utf8" instead of "utfmb4" for MySQL prior to 5.7.7
  encoding: utf8mb4
  variables:
    transaction_isolation: "READ-COMMITTED" 

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  adapter: mysql2
  database: redmine_test
  host: localhost
  username: root
  password: "" 
  # Use "utf8" instead of "utfmb4" for MySQL prior to 5.7.7
  encoding: utf8mb4
  variables:
    transaction_isolation: "READ-COMMITTED" 

RE: bundle exec rake db:migrate RAILS_ENV=production -> NoMethodError: undefined method `stringify_keys' for nil:NilClass (NoMethodError) - Added by David Gessel 3 months ago

Figured it out - The problem is I commented out the recommended required value for transaction_isolation and you'll note my confused insertion of the key tx_isolation for the value in the pair.

Commenting out the key causes a null value to be passed to /abstract_mysql_adapter.rb:744 which doesn't have any input sanitizing. The undefined method error message is terribly misleading as the actual problem is a null value. My clue was this fine post: NoMethodError: undefined method for nil:NilClass... Explained

Armed with that data, I needed to decode why any of the possible values for transaction_isolation created a different error:

$ bundle config set --local without 'development test'
You are replacing the current local value of without, which is currently "development:test" 
$ RAILS_ENV=production bundle exec rake db:migrate --trace
(in /usr/local/www/redmine)
** Invoke db:migrate (first_time)
** Invoke db:load_config (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute db:load_config
** Execute db:migrate
rake aborted!
ActiveRecord::StatementInvalid: Mysql2::Error: Unknown system variable 'transaction_isolation' (ActiveRecord::StatementInvalid)

This seemed easy to avoid by simply commenting out the recommended transaction_isolation declaration to get started.

It was not. Because above.

And it turns out that for MariaDB, at least MariaDB 10.5.16, the correct recommended required key value pair is:

tx_isolation: "READ-COMMITTED"

And after that, it's just the usual quirks of Ruby. Now to flush and restart with the historical data.

    (1-8/8)