Rails继承子类

时间:2016-03-09 19:28:32

标签: ruby-on-rails

我有三个类用户,驱动程序,公司。 每个公司或司机都属于一个用户。模型看起来像

 class Company < User
  has_many :driver
 end

 class Driver < User
 end

 class User < ActiveRecord::Base
  enum role: [:admin, :support, :B2B , :B2C]
 end

,数据库看起来像

class CreateUsers < ActiveRecord::Migration
 def change
 create_table :users do |t|
  t.string :email

  t.timestamps null: false
  end
 end
end

class CreateCompanies < ActiveRecord::Migration
 def change
  create_table :companies do |t|
   t.string :comp_name
   t.string :first_name_counterpart
   t.string :last_name_counterpart
   t.string :iban_nr
   t.string :bic
   t.string :email_counterpart
   t.string :addresse
   t.string :city
   t.string :zip

   t.references :user  
   t.timestamps null: false
  end
 end
end

class CreateDrivers < ActiveRecord::Migration
 def change
  create_table :drivers do |t|
   t.string :first_name
   t.string :last_name
   t.date :birthday
   t.integer :sex
   t.integer :dpi
   t.integer :score


   t.references :user
   t.timestamps null: false
  end
 end
end

为什么我不能创建Driver-instance。例如,如果我尝试d = Driver.new,我会获得一个用户实例。d = Driver.new => #<Driver id: nil, email: nil, created_at: nil, updated_at: nil>

2 个答案:

答案 0 :(得分:1)

这是Rails从模型类中猜测表名的方式。引用table_name的{​​{3}}:

  

根据继承层次结构直接从ActiveRecord::Base 降序的类的名称,猜测表名(强制小写)。因此,如果层次结构如下:Reply < Message < ActiveRecord::Base,那么即使在Message上调用,Reply也会用于猜测表名。

你应该能够通过table_name= setter强制使用正确的表名,例如:

class Driver < User
  self.table_name = "drivers"
end

另一方面,我也不确定你的方法(具有这种继承)不会在其他地方引起问题。

答案 1 :(得分:1)

如果您的模型具有继承性,请执行以下操作:

class User < ActiveRecord::Base
  enum role: [:admin, :support, :B2B , :B2C]
end

class Company < User
  has_many :driver
end

class Driver < User
end

rails推断您是在单表继承(STI)之后,并且期望只有一个基表users,其列type存储User的记录,CompanyDriver具有实际的班级名称(例如:CompanyDriver等)。

如果您希望拥有单独的表userscompaniesdrivers,因为每个表都有不同的列集,这是您将继承放入的唯一原因如果要共享一些常用功能,那么您应该将常用功能提取到modules并将它们混合到这些模型中(仅通过继承ActiveRecord::Base

rails,通过active_support提供了名为concerns的内容,将常用功能提取到模块中并直观地混合。

你可能可以逃避继承,并且仍然让这些模型指向具有self.table_name = "table_name"声明的单独表。但这并不是一个好主意,因为它绕过rails惯例并可能导致问题。

有关详细信息,请参阅ActiveRecord::InheritanceActiveSupport::Concern