【问题标题】:Subclass models in subfolders are not autoloaded子文件夹中的子类模型不会自动加载
【发布时间】:2014-06-25 05:38:48
【问题描述】:

我的一些模型有两个级别的继承:(这些都在 /app/models 中)

A.rb
/A/B1.rb
/A/B1/C1.rb
/A/B1/C2.rb
/A/B1/C3.rb
/A/B2.rb
/A/B2/C1.rb
/A/B2/C2.rb
/A/B2/C3.rb
...

A.rb 很简单:

class A
  def self.inherited(subclass)
    puts "New subclass: #{subclass}"
  end

  # some methods
end

B1.rb 是:

class A::B1 < A
  # some methods
end

C1.rb 是:

class A::B1::C1 < A::B1
  # some methods
end

您可以插入其余模型的外观。

当我加载 rails console 时,我看到了这个:

New subclass: A::B1
New subclass: A::B1::C1
New subclass: A::B2

请注意,A::B1::C2、A::B1::C3 和 A::B2 的子类都没有继承!这是为什么呢?

它变得更奇怪了。在rails console,我可以这样做:

irb(main)> A::B1::C2
New subclass: A::B1::C2
A::B1::C2 < A::B1
irb(main)> A::B2::C1
New subclass: A::B2::C1
A::B2::C1 < A::B2

所以我可以键入所有未继承的子类,然后它突然触发puts 消息。我认为这证明问题出在自动加载器上,而不是我的代码上。

这发生在我使用 Ruby 1.9 的开发环境中。和 Rails 3.2。

这是我的config.autoload_paths 声明:

config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]

提前致谢!

【问题讨论】:

  • 您的自动加载配置位于config/application.rb 中,可能如下所示:config.autoload_paths += %W(#{config.root}/lib... 是覆盖自动加载路径还是附加到它们?您应该使用rails console 加载Rails 上下文。 Rails 是 application.rbirb 仅适用于普通 Ruby。
  • 嘿@Chloe - 这就是我所拥有的:config.autoload_paths += %W(#{config.root}/lib)config.autoload_paths += Dir["#{config.root}/lib/**/"]
  • 你说得对——我一直在使用rails c。我会更新我的问题。谢谢!
  • 也可以试试class.parentclass.superclass 看看它会打印什么。 A::B1::C1.parentA::B1::C1.superclass.
  • A::B1::C1.parentA::B1::C1.superclass 都返回 A::B1 &lt; A。未自动加载的类返回相同的内容。

标签: ruby-on-rails ruby ruby-on-rails-3


【解决方案1】:

您需要在 config.autoload_paths 选项中包含各种模型:

#config/application.rb
config.autoload_paths += Dir[Rails.root.join('app', 'models', '{**}')]

这利用了globbing - 基本上将特定目录中的任何文件添加到您的路径中。我们将上面的代码用于单级目录(app/models/directory/1.rb);如果您想使用多个级别,则必须像这样指示它们:

Dir[Rails.root.join('app', 'models', '{*}', '{**}')]

【讨论】:

  • 不幸的是,这不起作用。 puts config.autoload_paths 确实打印了所有 C1.rb、C2.rb 等文件,所以我可以告诉我我的路径是正确的。然而,同一组类打印New subclass(与以前完全相同)。
【解决方案2】:

我希望我有一个更好的答案,但就 Sergio 而言,我的子类从未被直接提及,因此它们不会自动加载。

我真的不得不把它们写在我的类文件的顶部:

B1.rb:

class A1::B1

  A1::B1::C1 # simply mentioning the class autoloads it
  A1::B2::C2
  ...

  def foo
    ...
  end

end

【讨论】:

    【解决方案3】:

    这可能为时已晚,无法帮助您,但我遇到了同样的问题,因此希望此答案对其他人有所帮助。

    如果您使用的是Spring gem,那么您的应用程序实际上是在后台运行的。因此,简单地重新启动不会重新运行初始化程序,也不会将这些目录添加到您的自动加载路径中。

    您想运行bin/spring stop,以便在您重新启动应用程序时运行初始化程序。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-21
      • 2014-01-12
      • 1970-01-01
      • 2019-10-20
      • 2012-06-16
      • 2014-10-26
      • 2016-09-22
      • 1970-01-01
      相关资源
      最近更新 更多