Skip to content

Commit

Permalink
restore 2.x config loading behavior
Browse files Browse the repository at this point in the history
Attempt to restore 2.x config loading behavior where 1) per-model config blocks
only evaluate after all the models are loaded and associations are defined
while 2) initializer config block evaluates immediately so that routes are
configured correctly.

One remaining change compared to 2.x is RailsAdmin::Config#model no longer
returns the model when given a block. With the removal of LazyModel in e4ae669
it is tricky to both defer initialization and return the model class.

Fixes #3490
  • Loading branch information
q3aiml committed Mar 10, 2022
1 parent 837fe71 commit 5696edb
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 16 deletions.
2 changes: 1 addition & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ Metrics/MethodLength:
Max: 29 # TODO: Lower to 15

Metrics/ModuleLength:
Max: 217 # TODO: Lower to 100
Max: 227 # TODO: Lower to 100

Metrics/ParameterLists:
Max: 8 # TODO: Lower to 4
Expand Down
4 changes: 3 additions & 1 deletion lib/rails_admin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ def self.config(entity = nil, &block)
if entity
RailsAdmin::Config.model(entity, &block)
elsif block_given?
RailsAdmin::Config.apply(&block)
# Immediately evaluate non-model (initializer) config. It's needed to
# properly configure routes when there are custom actions.
yield RailsAdmin::Config
else
RailsAdmin::Config
end
Expand Down
4 changes: 1 addition & 3 deletions lib/rails_admin/adapters/mongoid/extension.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ module Extension
self.nested_attributes_options = {}
class << self
def rails_admin(&block)
RailsAdmin.config do |config|
config.model(self, &block)
end
RailsAdmin.config(self, &block)
end

alias_method :accepts_nested_attributes_for_without_rails_admin, :accepts_nested_attributes_for
Expand Down
32 changes: 26 additions & 6 deletions lib/rails_admin/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ module Config

# Variables to track initialization process
@initialized = false
@initializing = false
@deferred_blocks = []

class << self
Expand Down Expand Up @@ -87,6 +88,9 @@ class << self

# Finish initialization by executing deferred configuration blocks
def initialize!
return if @initializing

@initializing = true
@deferred_blocks.each { |block| block.call(self) }
@deferred_blocks.clear
@initialized = true
Expand Down Expand Up @@ -226,6 +230,7 @@ def default_search_operator=(operator)

# pool of all found model names from the whole application
def models_pool
initialize!
(viable_models - excluded_models.collect(&:to_s)).uniq.sort
end

Expand All @@ -238,7 +243,7 @@ def models_pool
#
# If a block is given it is evaluated in the context of configuration instance.
#
# Returns given model's configuration
# Otherwise returns given model's configuration.
#
# @see RailsAdmin::Config.registry
def model(entity, &block)
Expand All @@ -254,9 +259,24 @@ def model(entity, &block)
entity.class.name.to_sym
end

@registry[key] ||= RailsAdmin::Config::Model.new(entity)
@registry[key].instance_eval(&block) if block && @registry[key].abstract_model
@registry[key]
# When a block is provided defer evaluation until initialize so that:
#
# 1) performing configuration in the initializer does not attempt to
# autoload model classes, and
# 2) model config blocks run after models are fully loaded and
# associations are defined.
#
# Do not defer when called without a block as the model must be returned.
if block
RailsAdmin::Config.apply do
m = model(entity)
m.instance_eval(&block) if @registry[key].abstract_model
end
nil
else
initialize!
@registry[key] ||= RailsAdmin::Config::Model.new(entity)
end
end

def asset_source
Expand Down Expand Up @@ -318,6 +338,8 @@ def models
#
# @see RailsAdmin::Config.registry
def reset
@initialized = @initializing = false
@deferred_blocks.clear
@compact_show_view = true
@browser_validations = true
@authenticate = nil
Expand Down Expand Up @@ -356,10 +378,8 @@ def reset_model(model)

# Perform reset, then load RailsAdmin initializer again
def reload!
@initialized = false
reset
load RailsAdmin::Engine.config.initializer_path
initialize!
end

# Get all models that are configured as visible sorted by their weight and label.
Expand Down
5 changes: 0 additions & 5 deletions lib/rails_admin/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,6 @@ class Engine < Rails::Engine
ERROR
end

RailsAdmin::Config.initialize!

# Force route reload, since it doesn't reflect RailsAdmin action configuration yet
app.reload_routes!

RailsAdmin::Version.warn_with_js_version
end
end
Expand Down
24 changes: 24 additions & 0 deletions spec/rails_admin/config_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,24 @@ class TestController < ActionController::Base; end
end
end

context 'when a block is not provided' do
let(:model) { described_class.model(Team) }
it 'returns the model config' do
expect(model).to be_a(RailsAdmin::Config::Model)
end
end

context 'when a block is provided' do
let(:model) do
described_class.model(Team) do
field :fans
end
end
it 'does not return the model config' do
expect(model).to be_nil
end
end

context 'when model expanded' do
before do
described_class.model(Team) do
Expand Down Expand Up @@ -387,6 +405,7 @@ class TestController < ActionController::Base; end
end
end
before { RailsAdmin::Config.instance_variable_set(:@initialized, false) }
before { RailsAdmin::Config.instance_variable_set(:@initializing, false) }
after do
RailsAdmin::Config.instance_variable_set(:@initialized, true)
RailsAdmin::Config.instance_variable_set(:@deferred_blocks, [])
Expand Down Expand Up @@ -445,6 +464,11 @@ class TestController < ActionController::Base; end
expect(RailsAdmin::Config.model(Team).fields.find { |f| f.name == :color }.type).to eq :color
end

it 'does not immediately apply model configuration' do
expect(RailsAdmin::Config).not_to receive(:initialize!)
RailsAdmin::Config.reload!
end

it "applies the initializer's configuration first, then models' configurations" do
# simulate the situation that Team model is loaded in the middle of processing RailsAdmin initializer
allow_any_instance_of(RailsAdmin::Config::Model).to receive(:include_all_fields).and_wrap_original do |method|
Expand Down

0 comments on commit 5696edb

Please sign in to comment.