Принуждение рельсов к автозагрузке класса

У меня есть несколько небольших классов, которые находятся в одном файле в /app/models, например:

# /app/models/little_class.rb
class LittleClass; ...do stuff; end;
class AnotherLittleClass; ...do stuff; end;

Rails, кажется, предназначен только для автоматической загрузки классов в файлах, отражающих имя класса. Таким образом, ссылка на AnotherLittleClass за пределами файла вызывает ошибки «неинициализированной константы», как показано ниже, до тех пор, пока не будет указана ссылка на LittleClass:

irb(main):001:0> AnotherLittleClass 
NameError: uninitialized constant AnotherLittleClass
irb(main):02:0> LittleClass
=> LittleClass
irb(main):03:0> AnotherLittleClass
=> LittleClass2

Было бы больно и грязно разбивать их на отдельные файлы. Есть ли способ автозагрузки этих классов, чтобы ссылка на AnotherLittleClass без LittleClass не вызывала ошибку?


person Allyl Isocyanate    schedule 07.04.2012    source источник


Ответы (4)


Попробуйте этот трюк:

1.9.2p312 :001 > AnotherLittleClass.new
# => NameError: uninitialized constant AnotherLittleClass
1.9.2p312 :002 > autoload :AnotherLittleClass, File.dirname(__FILE__) + "/app/models/little_class.rb"
# => nil 
1.9.2p312 :003 > AnotherLittleClass.new
# => #<AnotherLittleClass:0xa687d24> 
person WarHog    schedule 07.04.2012
comment
Хм, это понятно. Облом, что мне приходится вручную указывать все классы. Спасибо @WarHog - person Allyl Isocyanate; 08.04.2012
comment
Однако этот трюк нарушит перезагрузку классов Rails, если вы об этом заботитесь. Поэтому, если вы внесете какие-либо изменения в эти классы, вам придется перезапустить приложение. - person Laura Paakkinen; 07.04.2016

Вы можете поместить их в модуль и использовать в этом пространстве имен SomeLittleClasses::LittleClass.do_something

# /app/models/some_little_classes.rb
module SomeLittleClasses

  class LittleClass
    def self.do_something
      "Hello World!"
    end
  end

  class AnotherLittleClass
    def self.do_something
      "Hello World!"
    end
  end

end
person Community    schedule 07.04.2012

Это ваш выбор, как я его вижу:

  1. разделите ваш файл на один файл для каждого класса, поместите их в каталог с именем в соответствии с соглашением rails (SomeClass => some_class.rb) и в файле запуска (скажем, создайте файл в config/initializers), вызовите:

    autoload_paths Rails.application.config.root + "/path/to/lib"
    
  2. добавьте что-то вроде этого в файл запуска:

    %W[
        Class1 Class2
        Class3 Class4 Class4
    ].map(&:to_sym).each dp |klass|
        autoload klass,Rails.application.config.root + "/path/to/lib/file"
    end
    

    Это, конечно, придется обновлять каждый раз, когда в файл добавляется новый класс.

  3. Переместите все классы в пространство имен модуля/класса и вызовите autoload, чтобы добавить его, как указано выше.

  4. просто загрузите весь файл заранее в файл запуска с помощью require. Спросите себя: оправдывают ли дополнительные усилия задержку загрузки этого файла?

person Michael Slade    schedule 08.04.2012

Дан следующий файл app/models/statistic.rb:

class Statistic
  # some model code here
end

class UsersStatistic < Statistic; end
class CommentsStatistic < Statistic; end
class ConnectionsStatistic < Statistic; end

Создайте файл config/initializers/autoload_classes.rb и добавьте следующий код:

# Autoloading subclasses that are in the same file


# This is the normal way to load single classes
#
# autoload :UsersStatistic, 'statistic'
# autoload :CommentsStatistic, 'statistic'
# autoload :ConnectionsStatistic, 'statistic'


# This is the most dynamic way for production and development environment.
Statistic.subclasses.each do |klass|
  autoload klass.to_s.to_sym, 'statistic'
end



# This does the same but loads all subclasses automatically. 
# Useful only in production environment because every file-change 
# needs a restart of the rails server.
# 
# Statistic.subclasses
person phlegx    schedule 10.08.2015