Marlin Pierce
Marlin Pierce

Reputation: 10079

Inherited class cannot find table

I have three models using inheritance, and a table named '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

When I do a create on the inherited class, it cannot find the table.

[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"

How do I get the inherited class to find the table? Keep in mind, I will need other inherited classes with different tables.

Upvotes: 0

Views: 1422

Answers (4)

carols10cents
carols10cents

Reputation: 7014

This looks like a bug in Rails 3.2 that is fixed in Rails 4.0.0.

ETA: Actually, you might need to add abstract class to fix your immediate problem but then hit this bug ;)

Also see this related Documentation commit.

ETA again: A closed rails issue sounds related as well; having non-abstract-classes and table-per-class inheritance looks unsupported.

Upvotes: 4

Aaron Gray
Aaron Gray

Reputation: 11703

Would modules and mixins handle this for you?

See here.

Upvotes: 0

engineerDave
engineerDave

Reputation: 3935

You have a lot of concepts at play here. Ruby Inheritance, Rails STI, and Namespacing.

First, it seems like you're confusing Ruby's Object Oriented Inheritance with Rails Single Table inheritance (STI) because they both confusingly use inheritance. However with STI the key takeaway is the words single table. Rails STI makes the assumption that all objects will be saved into one table and that the model will add their class name into the extra db column called type. This column needs to exist for STI to work. It also allows you to fetch them via their class_name

Telecom::Circuits::Base.all

or

Telecom::Circuits::AttVoice.all

Your code as I understand it should be

# 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

I took the liberty of making base and att_voice a subclass of circuits as I assumed that they are both independent types of circuits. If base has functionality that the other sub classes share and add on too then this class is redundant and the code would go into the Telecom::Circuit class.

If this isn't what you want, you're outside of the ActiveRecord model used in Rails. You may need to give each its own fully fledged table. Or perhaps you can utilize DataMapper or the new ROM to achieve your means.

Hope this helps!

Upvotes: 1

BvuRVKyUVlViVIc7
BvuRVKyUVlViVIc7

Reputation: 11811

You shouldnt inherit more than 1 level with rails, it becomes complicated and doesn't work very well. I had a similar structure and went back to only a single inheritance.

Im not sure if this works, but did you try it also with:

class BaseCircuit < ActiveRecord::Base
end

class Circuit < BaseCircuit
  ...
end

class AttVoiceCircuit < Circuit
  ...
end

so without namespaces? Table name should be "base_circuits"

Edit: In the answers someone suggested the problem is with more than one level of inheritance or namespaces. I tried the following:

class BaseSo < ActiveRecord::Base
end

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

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

with these results:

[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'

Upvotes: 0

Related Questions