Rails: организация моделей во вложенных папках с предупреждением: константа уровня заполнения A, на которую ссылается B:: A

Сегодня я решил реорганизовать большое количество моделей, связанных с пользователем, и у меня возникла проблема с ним.

Раньше у меня была такая структура:

app/models/user.rb
app/models/user_info.rb
app/models/user_file.rb
...

Итак, я переместил все модели user_ в подпапку пользователя следующим образом:

app/models/user.rb
app/models/user/info.rb
app/models/user/file.rb
...

и изменили свои определения на

class User::Info < ActiveRecord::Base
class User::File < ActiveRecord::Base
...

User модель не была изменена (кроме ассоциаций).

Все работает отлично, кроме модели User::File. Когда я пытаюсь получить доступ к этой модели, я получаю следующую ошибку:

warning: toplevel constant File referenced by User::File

и действительно, он возвращает стандартный класс файлов Ruby.

Что я делаю неправильно?

UPD1:

root# rails c
Loading development environment (Rails 3.2.13)
2.0.0p195 :001 > User::File
(irb):1: warning: toplevel constant File referenced by User::File
 => File
2.0.0p195 :002 > User::Info
 => User::Info(...)

UPD2:

2.0.0p195 :001 > User::SomeModel
NameError: uninitialized constant User::SomeModel
2.0.0p195 :002 > User::IO
(irb):2: warning: toplevel constant IO referenced by User::IO
 => IO 
2.0.0p195 :003 > User::Kernel
(irb):3: warning: toplevel constant Kernel referenced by User::Kernel
 => Kernel 

В моем приложении нет классов ввода-вывода или ядра, кроме стандартного ruby.

UPD3:

# app/models/user.rb
class User < ActiveRecord::Base
  has_many :files, class_name: 'User::File'
  ..
end

# app/models/user/file.rb
class User::File < ActiveRecord::Base
  belongs_to :user
  # some validations, nothing serious
end

Ответы

Ответ 1

Обновление: в этом году рождественский подарок был выпуском Ruby 2.5.0, с которым эта ошибка больше не будет. С Ruby 2.5+ вы получите либо константу, которую вы попросили, либо ошибку. Для более старых версий Ruby читайте:

Ваш класс User::File не загружен. Вы должны потребовать его (например, в user.rb).

Следующее происходит, когда ruby ​​/rails видит User::Info и оценивает его (упрощенный, только User еще не определен).

  • проверить, существует ли User::Info - это не (пока)
  • проверить, существует ли Info - это не (пока)
  • uninitialized constant → make reils magic, чтобы найти файл user/info.rb и потребовать его
  • return User::Info

Теперь давайте снова сделаем это для User::File

  • проверить, существует ли User::File - это не (пока)
  • проверить, существует ли File - это (потому что ruby ​​имеет встроенный класс File)!
  • выдать предупреждение, потому что нас попросили User::File, но получили ::File
  • return ::File

Заметим, что магия рельсов, которая автоматически требует файлов для (пока) неизвестных констант, не работает для User::File, потому что File не является неизвестным.

Ответ 2

Попробуйте обратиться к классу как User:: File, чтобы отличить его от обычных рубиновых файлов. Вы можете использовать:: File, чтобы ссылаться на те, когда они неоднозначны