From 6c43f92dfa76efd05dc8147a77c54af93a8149f9 Mon Sep 17 00:00:00 2001 From: Andy Clayton Date: Mon, 14 Mar 2022 14:18:52 -0500 Subject: [PATCH] maintain 3.x deferred initializer block config In 3.x the initializer config blocks are intentionally deferred to allow referencing model classes without quoting. Here is a first pass at keeping that behavior on top of ec03eb6f. It could probably use a little cleanup but here's an idea of an approach for feedback. See https://github.com/railsadminteam/rails_admin/pull/3492#issuecomment-1064915362 for details. --- .rubocop.yml | 4 +- lib/rails_admin.rb | 4 +- lib/rails_admin/config.rb | 64 +++++++++++++------ lib/rails_admin/engine.rb | 5 ++ .../config/initializers/rails_admin.rb | 2 +- spec/rails_admin/config_spec.rb | 29 +++++---- spec/spec_helper.rb | 1 + 7 files changed, 71 insertions(+), 38 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 812b176a02..09ddca0656 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -115,10 +115,10 @@ Metrics/CyclomaticComplexity: Metrics/MethodLength: CountComments: false - Max: 29 # TODO: Lower to 15 + Max: 30 # TODO: Lower to 15 Metrics/ModuleLength: - Max: 228 # TODO: Lower to 100 + Max: 249 # TODO: Lower to 100 Metrics/ParameterLists: Max: 8 # TODO: Lower to 4 diff --git a/lib/rails_admin.rb b/lib/rails_admin.rb index fee9e267d6..f58f254ade 100644 --- a/lib/rails_admin.rb +++ b/lib/rails_admin.rb @@ -29,9 +29,7 @@ def self.config(entity = nil, &block) if entity RailsAdmin::Config.model(entity, &block) elsif block_given? - # Immediately evaluate non-model (initializer) config. It's needed to - # properly configure routes when there are custom actions. - yield RailsAdmin::Config + RailsAdmin::Config.apply_core(&block) else RailsAdmin::Config end diff --git a/lib/rails_admin/config.rb b/lib/rails_admin/config.rb index 48c0426403..431c7eeace 100644 --- a/lib/rails_admin/config.rb +++ b/lib/rails_admin/config.rb @@ -23,9 +23,12 @@ module Config DEFAULT_CURRENT_USER = proc {} # Variables to track initialization process - @initialized = false - @initializing = false - @deferred_blocks = [] + @initialized_core = false + @initializing_core = false + @deferred_core_blocks = [] + @initialized_models = false + @initializing_models = false + @deferred_model_blocks = [] class << self # Application title, can be an array of two elements @@ -86,22 +89,42 @@ class << self # Set where RailsAdmin fetches JS/CSS from, defaults to :sprockets attr_writer :asset_source - # Finish initialization by executing deferred configuration blocks - def initialize! - return if @initializing + # Finish initialization by executing deferred non-model configuration blocks + def initialize_core! + return if @initializing_core - @initializing = true - @deferred_blocks.each { |block| block.call(self) } - @deferred_blocks.clear - @initialized = true + @initializing_core = true + @deferred_core_blocks.each { |block| block.call(self) } + @deferred_core_blocks.clear + @initialized_core = true end - # Evaluate the given block either immediately or lazily, based on initialization status. - def apply(&block) - if @initialized + # Evaluate the given non-model block either immediately or lazily, based on initialization status. + def apply_core(&block) + if @initialized_core yield(self) else - @deferred_blocks << block + @deferred_core_blocks << block + end + end + + # Finish initialization by executing deferred model configuration blocks + def initialize_models! + return if @initializing_models + + initialize_core! + @initializing_models = true + @deferred_model_blocks.each { |block| block.call(self) } + @deferred_model_blocks.clear + @initialized_models = true + end + + # Evaluate the given model block either immediately or lazily, based on initialization status. + def apply_model(&block) + if @initialized_models + yield(self) + else + @deferred_model_blocks << block end end @@ -230,7 +253,7 @@ def default_search_operator=(operator) # pool of all found model names from the whole application def models_pool - initialize! + initialize_models! (viable_models - excluded_models.collect(&:to_s)).uniq.sort end @@ -268,13 +291,13 @@ def model(entity, &block) # # Do not defer when called without a block as the model must be returned. if block - RailsAdmin::Config.apply do + RailsAdmin::Config.apply_model do m = model(entity) m.instance_eval(&block) if @registry[key].abstract_model end nil else - initialize! + initialize_models! @registry[key] ||= RailsAdmin::Config::Model.new(entity) end end @@ -338,8 +361,10 @@ def models # # @see RailsAdmin::Config.registry def reset - @initialized = @initializing = false - @deferred_blocks.clear + @initialized_core = @initializing_core = false + @deferred_core_blocks.clear + @initialized_models = @initializing_models = false + @deferred_model_blocks.clear @compact_show_view = true @browser_validations = true @authenticate = nil @@ -380,6 +405,7 @@ def reset_model(model) def reload! reset load RailsAdmin::Engine.config.initializer_path + initialize_core! end # Get all models that are configured as visible sorted by their weight and label. diff --git a/lib/rails_admin/engine.rb b/lib/rails_admin/engine.rb index b462fb557d..ef3042da21 100644 --- a/lib/rails_admin/engine.rb +++ b/lib/rails_admin/engine.rb @@ -68,6 +68,11 @@ class Engine < Rails::Engine ERROR end + RailsAdmin::Config.initialize_core! + + # Force route reload, since it doesn't reflect RailsAdmin action configuration yet + app.reload_routes! + RailsAdmin::Version.warn_with_js_version end end diff --git a/spec/dummy_app/config/initializers/rails_admin.rb b/spec/dummy_app/config/initializers/rails_admin.rb index 6f3d9b9ade..6f81505b39 100644 --- a/spec/dummy_app/config/initializers/rails_admin.rb +++ b/spec/dummy_app/config/initializers/rails_admin.rb @@ -2,7 +2,7 @@ RailsAdmin.config do |c| c.asset_source = CI_ASSET - c.model 'Team' do + c.model Team do include_all_fields field :color, :color end diff --git a/spec/rails_admin/config_spec.rb b/spec/rails_admin/config_spec.rb index bf1f27dd04..6fadce48e3 100644 --- a/spec/rails_admin/config_spec.rb +++ b/spec/rails_admin/config_spec.rb @@ -395,8 +395,8 @@ class TestController < ActionController::Base; end end end - describe '.apply' do - subject { RailsAdmin::Config.apply(&block) } + describe '.apply_core' do + subject { RailsAdmin::Config.apply_core(&block) } let(:block) do proc do |config| config.model Team do @@ -404,32 +404,35 @@ class TestController < ActionController::Base; end 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, []) - end + after { RailsAdmin::Config.reset } it "doesn't evaluate the block immediately" do expect_any_instance_of(RailsAdmin::Config::Model).not_to receive(:register_instance_option) subject end - it 'evaluates block when initialize! is finished' do + it "doesn't evaluate the block when initialize_core! is finished" do + expect_any_instance_of(RailsAdmin::Config::Model).not_to receive(:register_instance_option).with('parameter') + subject + RailsAdmin::Config.initialize_core! + end + + it 'evaluates block when initialize_models! is finished' do expect_any_instance_of(RailsAdmin::Config::Model).to receive(:register_instance_option).with('parameter') subject - RailsAdmin::Config.initialize! + RailsAdmin::Config.initialize_models! end it 'evaluates config block only once' do expect_any_instance_of(RailsAdmin::Config::Model).to receive(:register_instance_option).once.with('parameter') subject - RailsAdmin::Config.initialize! - RailsAdmin::Config.initialize! + RailsAdmin::Config.initialize_models! + RailsAdmin::Config.initialize_models! end context 'with a non-existent class' do + before { RailsAdmin::Config.reset } + let(:block) do proc do |config| config.model UnknownClass do @@ -465,7 +468,7 @@ class TestController < ActionController::Base; end end it 'does not immediately apply model configuration' do - expect(RailsAdmin::Config).not_to receive(:initialize!) + expect(RailsAdmin::Config).not_to receive(:initialize_models!) RailsAdmin::Config.reload! end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index e4d9fa8feb..e728bc5d3d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -93,6 +93,7 @@ DatabaseCleaner.start RailsAdmin::Config.reset RailsAdmin::Config.asset_source = CI_ASSET + RailsAdmin::Config.initialize_core! end config.after(:each) do