Skip to content

Commit e3e0bbe

Browse files
0x01f7ctran
authored andcommitted
Try to get proper loaded model when using Rails eager_load_paths (#535)
1 parent 9cdf2d3 commit e3e0bbe

File tree

2 files changed

+41
-16
lines changed

2 files changed

+41
-16
lines changed

lib/annotate/annotate_models.rb

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -711,11 +711,11 @@ def get_model_class(file)
711711
model_path = file.gsub(/\.rb$/, '')
712712
model_dir.each { |dir| model_path = model_path.gsub(/^#{dir}/, '').gsub(/^\//, '') }
713713
begin
714-
get_loaded_model(model_path) || raise(BadModelFileError.new)
714+
get_loaded_model(model_path, file) || raise(BadModelFileError.new)
715715
rescue LoadError
716716
# this is for non-rails projects, which don't get Rails auto-require magic
717717
file_path = File.expand_path(file)
718-
if File.file?(file_path) && silence_warnings { Kernel.require(file_path) }
718+
if File.file?(file_path) && Kernel.require(file_path)
719719
retry
720720
elsif model_path =~ /\//
721721
model_path = model_path.split('/')[1..-1].join('/').to_s
@@ -726,8 +726,24 @@ def get_model_class(file)
726726
end
727727
end
728728

729+
# Retrieve loaded model class
730+
def get_loaded_model(model_path, file)
731+
loaded_model_class = get_loaded_model_by_path(model_path)
732+
return loaded_model_class if loaded_model_class
733+
734+
# We cannot get loaded model when `model_path` is loaded by Rails
735+
# auto_load/eager_load paths. Try all possible model paths one by one.
736+
absolute_file = File.expand_path(file)
737+
model_paths =
738+
$LOAD_PATH.select { |path| absolute_file.include?(path) }
739+
.map { |path| absolute_file.sub(path, '').sub(/\.rb$/, '').sub(/^\//, '') }
740+
model_paths
741+
.map { |path| get_loaded_model_by_path(path) }
742+
.find { |loaded_model| !loaded_model.nil? }
743+
end
744+
729745
# Retrieve loaded model class by path to the file where it's supposed to be defined.
730-
def get_loaded_model(model_path)
746+
def get_loaded_model_by_path(model_path)
731747
ActiveSupport::Inflector.constantize(ActiveSupport::Inflector.camelize(model_path))
732748
rescue StandardError, LoadError
733749
# Revert to the old way but it is not really robust
@@ -858,15 +874,6 @@ def classified_sort(cols)
858874
([id] << rest_cols << timestamps << associations).flatten.compact
859875
end
860876

861-
# Ignore warnings for the duration of the block ()
862-
def silence_warnings
863-
old_verbose = $VERBOSE
864-
$VERBOSE = nil
865-
yield
866-
ensure
867-
$VERBOSE = old_verbose
868-
end
869-
870877
private
871878

872879
def with_comments?(klass, options)

spec/annotate/annotate_models_spec.rb

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,11 +1257,29 @@ class LoadedClass < ActiveRecord::Base
12571257
EOS
12581258
path = File.expand_path('loaded_class', AnnotateModels.model_dir[0])
12591259
Kernel.load "#{path}.rb"
1260-
expect(Kernel).not_to receive(:require).with(path)
1260+
expect(Kernel).not_to receive(:require)
12611261

12621262
expect(capturing(:stderr) do
12631263
check_class_name 'loaded_class.rb', 'LoadedClass'
1264-
end).not_to include('warning: already initialized constant LoadedClass::CONSTANT')
1264+
end).to be_blank
1265+
end
1266+
1267+
it 'should not require model files twice which is inside a subdirectory' do
1268+
dir = Array.new(8) { (0..9).to_a.sample(random: Random.new) }.join
1269+
$LOAD_PATH.unshift(File.join(AnnotateModels.model_dir[0], dir))
1270+
1271+
create "#{dir}/subdir_loaded_class.rb", <<-EOS
1272+
class SubdirLoadedClass < ActiveRecord::Base
1273+
CONSTANT = 1
1274+
end
1275+
EOS
1276+
path = File.expand_path("#{dir}/subdir_loaded_class", AnnotateModels.model_dir[0])
1277+
Kernel.load "#{path}.rb"
1278+
expect(Kernel).not_to receive(:require)
1279+
1280+
expect(capturing(:stderr) do
1281+
check_class_name "#{dir}/subdir_loaded_class.rb", 'SubdirLoadedClass'
1282+
end).to be_blank
12651283
end
12661284
end
12671285

@@ -1667,7 +1685,7 @@ class User < ActiveRecord::Base
16671685

16681686
describe "if a file can't be annotated" do
16691687
before do
1670-
allow(AnnotateModels).to receive(:get_loaded_model).with('user').and_return(nil)
1688+
allow(AnnotateModels).to receive(:get_loaded_model_by_path).with('user').and_return(nil)
16711689

16721690
write_model('user.rb', <<-EOS)
16731691
class User < ActiveRecord::Base
@@ -1697,7 +1715,7 @@ class User < ActiveRecord::Base
16971715

16981716
describe "if a file can't be deannotated" do
16991717
before do
1700-
allow(AnnotateModels).to receive(:get_loaded_model).with('user').and_return(nil)
1718+
allow(AnnotateModels).to receive(:get_loaded_model_by_path).with('user').and_return(nil)
17011719

17021720
write_model('user.rb', <<-EOS)
17031721
class User < ActiveRecord::Base

0 commit comments

Comments
 (0)