Skip to content

Commit e9962f2

Browse files
author
Sebastian Gassner
committed
sort blocks by Proc.source_path, to guarantee that blocks from config/initializers evaluate before blocks defined in app/models
1 parent 4ca8de4 commit e9962f2

File tree

1 file changed

+18
-24
lines changed

1 file changed

+18
-24
lines changed

lib/rails_admin/config/lazy_model.rb

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,19 @@ def add_deferred_block(&block)
1313
def method_missing(method, *args, &block)
1414
if !@model
1515
@model = RailsAdmin::Config::Model.new(@entity)
16-
# Configuration defined in the model class should take precedence
17-
# over configuration defined in initializers/rails_admin.rb.
16+
# When evaluating multiple configuration blocks, the order of
17+
# execution is important. As one would expect (in my opinion),
18+
# options defined within a resource should take precedence over
19+
# more general options defined in an initializer. This way,
20+
# general settings for a number of resources could be specified
21+
# in the initializer, while models could override these settings
22+
# later, if required.
1823
#
19-
# Due to the way the Rails initialization process works,
20-
# configuration blocks found in app/models/MODEL.rb are added to
21-
# @deferred_bocks before blocks defined in initializers/rails_admin.rb.
22-
# Executing blocks in the order of addition would yield unexpected
23-
# behaviour, as blocks from the initializer would overwrite settings
24-
# defined in model classes.
25-
#
26-
# In order to maintain the expected precedence (model configuration over
27-
# initializer configuration), all blocks are executed in reverse order.
28-
#
29-
# Given the following code containing initialization blocks:
24+
# CAVEAT: It cannot be guaranteed that blocks defined in an initializer
25+
# will be loaded (and adde to @deferred_blocks) first. For instance, if
26+
# the initializer references a model class before defining
27+
# a RailsAdmin configuration block, the configuration from the
28+
# resource will get added to @deferred_blocks first:
3029
#
3130
# # app/models/some_model.rb
3231
# class SomeModel
@@ -36,20 +35,15 @@ def method_missing(method, *args, &block)
3635
# end
3736
#
3837
# # config/initializers/rails_admin.rb
39-
# config.model SomeModel do
38+
# model = 'SomeModel'.constantize # blocks from SomeModel get loaded
39+
# model.config model do # blocks from initializer gets loaded
4040
# :
4141
# end
4242
#
43-
# The block from app/models/some_model.rb will be added to
44-
# @deferred_blocks in front of the one from config/initializers/rails_admin.rb.
45-
# In order to give precedence to the block from SomeModel,
46-
# execute blocks in reverse order.
47-
#
48-
# CAVEAT: if, for some reason, a model would specify multiple configuration
49-
# blocks, later blocks would be executed before earlier blocks - which could
50-
# result in unexpected behaviour. However (and therefore), defining multiple
51-
# configuration blocks within a single model class are discouraged.
52-
@deferred_blocks.flatten.reverse.each do |block|
43+
# Thus, sort all blocks to excute for a resource by Proc.source_path,
44+
# to guarantee that blocks from 'config/initializers' evaluate before
45+
# blocks defined within a model class.
46+
@deferred_blocks.flatten.sort_by{|p| p.source_location.first =~ /config\/initializers/ ? 0 : 1}.each do |block|
5347
@model.instance_eval(&block)
5448
end
5549
end

0 commit comments

Comments
 (0)