Skip to content

Problem migration with not (yet) existing fields: NoMethodError: undefined method `defined' for nil:NilClass unless f.defined #3546

@jklimke

Description

@jklimke

Situation:

A developer that has to execute the added migrations to its development database. As there were many fields (e.g., :short_name) added to some models, there are referenced in Rails admin concerns, e.g.,

module Admin
  module AssetPropertyAdmin
    extend ActiveSupport::Concern

    included do
     rails_admin do
         # :short_name is added in a migration that has not been executed yet.
         fields :short_name, :name
     end
   end
  end
end

We are then not able to execute the migrations or start the server as the initialization of rails admin does not proceed.

The following error is thrown

rake aborted!
NoMethodError: undefined method `defined' for nil:NilClass
          unless f.defined
                  ^^^^^^^^
/home/user/.rvm/gems/ruby-3.1.2/gems/rails_admin-3.1.0.beta/lib/rails_admin/config/has_fields.rb:93:in `block in fields'
/home/user/.rvm/gems/ruby-3.1.2/gems/rails_admin-3.1.0.beta/lib/rails_admin/config/has_fields.rb:92:in `collect'
/home/user/.rvm/gems/ruby-3.1.2/gems/rails_admin-3.1.0.beta/lib/rails_admin/config/has_fields.rb:92:in `fields'
/home/user/projects/rails_app/app/models/concerns/admin/asset_property_admin.rb:25:in `block (3 levels) in <module:AssetPropertyAdmin>'
/home/user/.rvm/gems/ruby-3.1.2/gems/rails_admin-3.1.0.beta/lib/rails_admin/config/sections.rb:32:in `instance_eval'
/home/user/.rvm/gems/ruby-3.1.2/gems/rails_admin-3.1.0.beta/lib/rails_admin/config/sections.rb:32:in `block (2 levels) in included'
/home/user/projects/rails_app/app/models/concerns/admin/asset_property_admin.rb:24:in `block (2 levels) in <module:AssetPropertyAdmin>'
/home/user/.rvm/gems/ruby-3.1.2/gems/rails_admin-3.1.0.beta/lib/rails_admin/config.rb:261:in `instance_eval'
/home/user/.rvm/gems/ruby-3.1.2/gems/rails_admin-3.1.0.beta/lib/rails_admin/config.rb:261:in `model'
/home/user/.rvm/gems/ruby-3.1.2/gems/rails_admin-3.1.0.beta/config/initializers/active_record_extensions.rb:8:in `block in rails_admin'
/home/user/.rvm/gems/ruby-3.1.2/gems/rails_admin-3.1.0.beta/lib/rails_admin/config.rb:93:in `block in initialize!'
/home/user/.rvm/gems/ruby-3.1.2/gems/rails_admin-3.1.0.beta/lib/rails_admin/config.rb:93:in `each'
/home/user/.rvm/gems/ruby-3.1.2/gems/rails_admin-3.1.0.beta/lib/rails_admin/config.rb:93:in `initialize!'
/home/user/.rvm/gems/ruby-3.1.2/gems/rails_admin-3.1.0.beta/lib/rails_admin/engine.rb:39:in `block in <class:Engine>'
/home/user/.rvm/gems/ruby-3.1.2/gems/railties-6.1.6/lib/rails/initializable.rb:32:in `instance_exec'
/home/user/.rvm/gems/ruby-3.1.2/gems/railties-6.1.6/lib/rails/initializable.rb:32:in `run'
/home/user/.rvm/gems/ruby-3.1.2/gems/railties-6.1.6/lib/rails/initializable.rb:61:in `block in run_initializers'
/home/user/.rvm/gems/ruby-3.1.2/gems/railties-6.1.6/lib/rails/initializable.rb:60:in `run_initializers'
/home/user/.rvm/gems/ruby-3.1.2/gems/railties-6.1.6/lib/rails/application.rb:391:in `initialize!'
/home/user/projects/rails_app/config/environment.rb:5:in `<main>'
/home/user/.rvm/gems/ruby-3.1.2/gems/bootsnap-1.12.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
/home/user/.rvm/gems/ruby-3.1.2/gems/bootsnap-1.12.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:30:in `require'
/home/user/.rvm/gems/ruby-3.1.2/gems/zeitwerk-2.6.0/lib/zeitwerk/kernel.rb:35:in `require'
/home/user/.rvm/gems/ruby-3.1.2/gems/activesupport-6.1.6/lib/active_support/dependencies.rb:332:in `block in require'
/home/user/.rvm/gems/ruby-3.1.2/gems/activesupport-6.1.6/lib/active_support/dependencies.rb:299:in `load_dependency'
/home/user/.rvm/gems/ruby-3.1.2/gems/activesupport-6.1.6/lib/active_support/dependencies.rb:332:in `require'
/home/user/.rvm/gems/ruby-3.1.2/gems/railties-6.1.6/lib/rails/application.rb:367:in `require_environment!'
/home/user/.rvm/gems/ruby-3.1.2/gems/railties-6.1.6/lib/rails/application.rb:533:in `block in run_tasks_blocks'
/home/user/.rvm/gems/ruby-3.1.2/gems/airbrake-10.0.6/lib/airbrake/rake.rb:19:in `execute'
/home/user/.rvm/gems/ruby-3.1.2/bin/ruby_executable_hooks:22:in `eval'
/home/user/.rvm/gems/ruby-3.1.2/bin/ruby_executable_hooks:22:in `<main>'
Tasks: TOP => db:migrate => db:load_config => environment
(See full trace by running task with --trace)

How is it meant to work ?

It seems that this line can in fact return nil members in the array:

defined = field_names.collect { |field_name| _fields.detect { |f| f.name == field_name } }

that causes the follwing block to fail:

defined.collect do |f|

it can be fixed by compacting the defined array.

defined.compact.collect do |f|
  unless f.defined
    f.defined = true
    f.order = _fields.count(&:defined)
  end
  f.instance_eval(&block) if block
  f
end

Any oppinions on that ? Could you either apply the change or provide a hint how could this be avoided that rails admin crashes on not (yet) existing fields ?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions