Rails命名空间和STI问题 - 自动加载

时间:2015-10-22 15:36:07

标签: ruby-on-rails ruby-on-rails-4

我需要一些帮助来重组Rails应用程序。您可以在下面找到额外的细节。主要问题:

我在@Nathan建议之后修改了代码。向天堂迈进一步,但仍能闻到一些硫磺。

  • 已解决:为什么我收到错误:"类报告的超类不匹配"
  • 已解决:我是否可以制定一些指南,如何在Rails4中构建复杂的名称空间,扩展和STI?
  • 服务器重启后,我在Spock主页上收到错误: - "无法自动加载常量桥,预期......路由到此处... app / models / spock / report / bridge.rb定义它" - 刷新页面后,错误消失了。但仍然表明存在一些问题。每次重启服务器后都可以重现。提示:可能是自动加载问题......欢迎任何想法。

环境:

  • WEBrick 1.3.1
  • Rails 4.0.9
  • Ruby 2.1.5

错误详情:

Unable to autoload constant Bridge, expected ...route goes here... bridge.rb to define it

app/views/spock/spock/index.html.erb:11:in `block in _app_views_spock_spock_index_html_erb___3895075684249237486_132397353980'
app/views/spock/spock/index.html.erb:6:in `map'
app/views/spock/spock/index.html.erb:6:in `_app_views_spock_spock_index_html_erb___3895075684249237486_132397353980'

文件结构:

/app/controllers/spock/spock_controller.rb
/app/controllers/spock/marketplaces_controller.rb
/app/controllers/spock/reports_controller.rb

/app/modules/spock/spock_connector.rb
/app/modules/spock/report.rb
/app/modules/spock/report/bridge.rb
/app/modules/spock/report/metric.rb

文件:

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

# routes.rb
namespace :spock do
  get '/', :to => 'spock#index'
  resources :marketplaces, only: [] do
    resources :reports,    only: [:show]
end

# spock_controller.rb
module Spock
  class SpockController < ApplicationController
    def index
      @report_categories = Spock::Report.distinct.pluck(:category)
...

# marketplaces_controller
module Spock
  class MarketplacesController < SpockController
  end
end

# reports_controller
module Spock
  class ReportsController < MarketplacesController
    helper SpockHelper
...

# spock_connector.rb
module Spock
  class SpockConnector < ::ActiveRecord::Base
    self.abstract_class = true
    establish_connection "spock_#{Rails.env}"
  end
end

# report.rb
module Spock
  class Report < SpockConnector
    attr_accessor :legal_entity
  end
end

# bridge.rb
module Spock
  class Bridge < Report
...

# metric.rb
module Spock
  class Metric < Report
...

数据库:

/* reports table */
id, type,           category,
1   Spock::Bridge  Bridge
2   Spock::Metric  Metric

2 个答案:

答案 0 :(得分:0)

您正在3个单独的文件中打开/定义Report类。

report.rb中,您指定::Spock::SpockConnector作为Report的超类,但在bridge.rbmetric.rb中,您不是指定显式超类,因此Ruby使用Object作为其超类。

您不能同时拥有Object ::Spock::SpockConnector作为Report的直接超类。

解决方案:   在所有3个文件中,您需要使用class Report < ::Spock::SpockConnector

一旦你解决了这个问题,你就会遇到类似的错误,因为你在几个文件中打开SpockConnector,一次用::ActiveRecord::Base作为超类,有时用隐式{{1}打开作为超类。

这是另一个矛盾,因此在所有打开/定义Object的文件中,您需要使用SpockConnector作为超类。

至于你的命名空间问题,这是基于意见的,但我会说在Ruby中没有需要在命名空间内嵌套子类。

例如,您可以::ActiveRecord::BaseReportSpockConnectorMetric全部保留在同一命名空间级别:

Bridge

完全范围的名称是:

module Spock
  class SpockConnector < ActiveRecord::Base
  end
end

module Spock
  class Report < SpockConnector
  end
end

module Spock
  class Metric < Report
  end
end

module Spock
  class Bridge < Report
  end
end

答案 1 :(得分:0)

行。经过一天的反复试验后,我找到了自动加载问题的原因。

如果您发现自己触摸自动加载结构,那么这是一个错误路径的好兆头。 所以我从application.rb文件中删除了自动加载路径。

稍微修改了STI类,以匹配Rails自动加载逻辑;

# bridge.rb
module Spock
  class Report
    class Bridge < Report
...

# metric.rb
module Spock
  class Report
    class Metric < Report
...

数据库:

/* reports table */
id, type,           category,
1   Spock::Report::Bridge  Bridge
2   Spock::Report::Metric  Metric

在超类中包含STI类使得它们能够从子文件夹自动加载,而不必在application.rb文件中明确包含该文件夹。 缺点是类绝对路径变得更长......