【问题标题】:Inherited class cannot find table继承的类找不到表
【发布时间】:2013-09-10 13:22:40
【问题描述】:

我有三个使用继承的模型,以及一个名为“telecom_circuits”的表。

class Telecom::Circuits::BaseCircuit < ActiveRecord::Base
end

class Telecom::Circuit < ::Telecom::Circuits::BaseCircuit
  ...
end

class Telecom::Circuits::AttVoiceCircuit < ::Telecom::Circuit
  self.table_name = 'telecom_circuits'
end

当我对继承的类进行创建时,它找不到表。

[1] pry(main)> Telecom::Circuits::AttVoiceCircuit
=> Telecom::Circuits::AttVoiceCircuit(id: integer, user_id: integer, division_id: integer, raw_site_id: integer, install_date: date, saville_account_number: string, account_number: string, meg8_account_number: string, main_circuit_id: string, d_channel: string, d_channel_type: string, ds3_access_circuit_id: string, lec_circuit_id: string, cli: string, lso: string, apn_ct1: string, dchan_cost: decimal, monthly_recurring_cost: decimal, created_at: datetime, updated_at: datetime, circuit_provision_type: string, trunk_group: string, apn_ct2: string, slot: string, disconnect_date: datetime, disconnect_requester_id: integer, disconnect_processor_id: integer, telecom_site_id: integer)
[2] pry(main)> Telecom::Circuits::AttVoiceCircuit.create
ActiveRecord::StatementInvalid: Mysql2::Error: Table 'itrc_dev.telecom_base_circuits' doesn't exist: SHOW FULL FIELDS FROM `telecom_base_circuits`
from /Users/mpierc200/.rvm/gems/ruby-1.9.3-p327@itrc/gems/activerecord-3.2.14/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:245:in `query'
[3] pry(main)> Telecom::Circuits::AttVoiceCircuit.table_name
=> "telecom_circuits"

如何让继承的类找到表?请记住,我将需要具有不同表的其他继承类。

【问题讨论】:

  • self.table_name = ... 或 set_table_name ... 的结果相同
  • 所以你的类使用继承,但你有每个类的表(即你没有单表继承)?
  • 正确。我正在使用多表继承,每个继承类都有一个表,但基类没有。
  • Telecom::Circuit.table_nameTelecom::Circuits::BaseCircuit.table_name 的结果是什么?
  • Telecom::Circuits::BaseCircuit.table_name => "telecom_base_circuits" Telecom::Circuit.table_name => "telecom_base_circuits"

标签: ruby-on-rails inheritance activerecord ruby-on-rails-3.2


【解决方案1】:

这看起来像是 Rails 3.2 中的一个错误,即 fixed in Rails 4.0.0

ETA:实际上,您可能需要add abstract class 来解决您当前的问题,但随后遇到了这个错误;)

另见此相关Documentation commit

ETA 再次:A closed rails issue 听起来也相关;具有非抽象类和每类表的继承看起来不受支持。

【讨论】:

  • 我还发现如果我设置 self.superclass.table_name 和 ALSO set self.table_name 它可以工作。
  • 哎呀,不得不这样做真是太糟糕了。
【解决方案2】:

这里有很多概念。 Ruby 继承、Rails STI 和命名空间。

首先,您似乎将 Ruby 的面向对象继承与 Rails 单表继承 (STI) 混淆了,因为它们都混淆了继承。然而,对于 STI,关键的要点是 single table 一词。 Rails STI 假设所有对象都将保存到一个表中,并且模型会将它们的类名添加到名为 type 的额外 db 列中。此列需要存在才能使 STI 正常工作。它还允许您通过它们的 class_name

获取它们
Telecom::Circuits::Base.all

Telecom::Circuits::AttVoice.all

我理解的你的代码应该是

# in app/telecom/circuit.rb
class Telecom::Circuit < ActiveRecord::Base
  ...
end

# in app/telecom/circuits/base.rb
class Telecom::Circuits::Base < Telecom::Circuit
  ...
end

# in app/telecom/circuits/att_voice.rb    
class Telecom::Circuits::AttVoice < Telecom::Circuit
  ... 
end

我冒昧地将 base 和 att_voice 设为电路的子类,因为我假设它们都是独立的电路类型。如果 base 具有其他子类共享和添加的功能,那么这个类是多余的,代码将进入 Telecom::Circuit 类。

如果这不是您想要的,那么您就超出了 Rails 中使用的 ActiveRecord 模型。您可能需要为每个人提供自己的完整表格。或者也许您可以利用DataMapper 或新的ROM 来实现您的目的。

希望这会有所帮助!

【讨论】:

  • 我正在尝试使用多表继承。我意识到 Rails 专注于 STI,并且非常支持它。但是,我过去曾这样做过,并让它发挥作用。我不明白为什么 Rails 不应该支持这一点,它让它只差了一步。一切正常,但创建失败。
【解决方案3】:

你不应该用 Rails 继承超过 1 个级别,它会变得复杂并且不能很好地工作。我有一个类似的结构,然后回到只有一个继承。

我不确定这是否有效,但您是否也尝试过:

class BaseCircuit < ActiveRecord::Base
end

class Circuit < BaseCircuit
  ...
end

class AttVoiceCircuit < Circuit
  ...
end

所以没有命名空间?表名应为“base_circuits”

编辑: 在有人建议的答案中,问题出在不止一层继承或命名空间上。我尝试了以下方法:

class BaseSo < ActiveRecord::Base
end

class AttVoice < BaseSo
  self.table_name = 'telecom_circuits'
end

class ComcastVoice < BaseSo
  self.table_name = 'telecom_pri_circuits'
end

这些结果:

[1]pry(main)> AttVoice
=> AttVoice(id: integer, user_id: integer, division_id: integer, raw_site_id: integer, install_date: date, saville_account_number: string, account_number: string, meg8_account_number: string, main_circuit_id: string, d_channel: string, d_channel_type: string, ds3_access_circuit_id: string, lec_circuit_id: string, cli: string, lso: string, apn_ct1: string, dchan_cost: decimal, monthly_recurring_cost: decimal, created_at: datetime, updated_at: datetime, circuit_provision_type: string, trunk_group: string, apn_ct2: string, slot: string, disconnect_date: datetime, disconnect_requester_id: integer, disconnect_processor_id: integer, telecom_site_id: integer)
[2] pry(main)> AttVoice.table_name
=> "telecom_circuits"
[3] pry(main)> ComcastVoice
=> ComcastVoice(id: integer, created_at: datetime, updated_at: datetime, order_submitter: string, division_id: integer, lead_id: integer, pin: integer, raw_site_id: integer, site_poc: string, install_date: date, csg_billing_number: string, gl_code: string, pri_count: integer, pri_type: string, port_native: boolean, did_range: string, did_count: integer, comments: string, telecom_site_id: integer)
[4] pry(main)> ComcastVoice.table_name
=> "telecom_pri_circuits"
[5] pry(main)> AttVoice.count
(41.8ms)  SELECT COUNT(*) FROM `telecom_circuits` 
=> 2247
[6] pry(main)> AttVoice.create
ActiveRecord::StatementInvalid: Mysql2::Error: Table 'itrc_dev.base_sos' doesn't exist: SHOW FULL FIELDS FROM `base_sos`
from /Users/mpierc200/.rvm/gems/ruby-1.9.3-p327@itrc/gems/activerecord-3.2.14/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:245:in `query'
[7] pry(main)> ComcastVoice.count
(0.4ms)  SELECT COUNT(*) FROM `telecom_pri_circuits` 
=> 155
[8] pry(main)> ComcastVoice.create
ActiveRecord::StatementInvalid: Mysql2::Error: Table 'itrc_dev.base_sos' doesn't exist: SHOW FULL FIELDS FROM `base_sos`
from /Users/mpierc200/.rvm/gems/ruby-1.9.3-p327@itrc/gems/activerecord-3.2.14/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:245:in `query'

【讨论】:

  • 这两个级别是临时的,而我将 Telecom::Circuit 重构为基类和继承的 AttVoiceCircuit。我希望一个可靠的编程语言和 Web 环境能够处理任意数量的继承级别。
  • 也许你应该尝试不使用命名空间
  • 您是否创建了名为 base_sos 的表?
  • 一般情况下如果做继承就是只用一个表
  • 如果您使用多个表,为什么要进行继承?制作一些模块并将它们包含在类中可能会更好?
【解决方案4】:

模块和 mixin 会为您处理这个问题吗?

here

【讨论】:

  • 我正在尝试将公共属性移动到公共 Circuit 类中,因此我正在尝试做的事情与示例相匹配。
  • 它会起作用,并且可以通过更改“基”类(或在本例中为模块)来更改我所有继承的类。我试图使用继承有几个原因。一、我有很强的isa关系,所以想使用一级继承机制。第二,我发现将 has_one 放在一个模块中会对该模块进行耦合,并对模块可以包含的内容进行限制。当耦合被其他继承覆盖时,我感觉更舒服。也就是说,该模块的一个假设是它是一个 AR 类,因此它可以调用 has_one。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-17
  • 2011-08-29
  • 1970-01-01
  • 2016-06-28
相关资源
最近更新 更多