Prezes Łukasz
Prezes Łukasz

Reputation: 968

Create correct inheritance

I have problem with creating proper inheritance between classes in Ruby On Rails.

Idea: There are 2 classes: Person and Client. Person is a abstract class and Client inherits Person attribute.

Problem: My solution doesn't work. I don't know why. How can I correctly implement (prefer CTI) inheritance.

Migrations:

create_persons.rb

class CreatePersons < ActiveRecord::Migration
  def self.up
    create_table :persons do |t|
      t.string :pesel, null: false
      t.string :first_name, null: false
      t.string :last_name, null: false
      t.string :email, null: false
      t.date :data_of_birth, null: false
      t.string :password_digest, null: false
      # required for STI
      t.string :type
      t.timestamps null: false
    end
  end

  def self.down
    drop_table :persons
  end
end

create_clients.rb

class CreateClients < ActiveRecord::Migration
  def change
    create_table :clients do |t|
      add_foreign_key :persons
      t.timestamps null: false
    end
  end
end

Model Person

class Person < ActiveRecord::Base
  self.abstract_class = true
end

Model Client

class Client < Person

end

After db:migrate, when I try Client.create(pesel: "1232",....) there is error: unknown attribute 'pesel' for Client.

Upvotes: 1

Views: 139

Answers (2)

Cyril Lavedrine
Cyril Lavedrine

Reputation: 161

Single Table Inheritance is based upon having a single table to store all the records. Your problem is that you create a table 'clients' which Rails uses by default for the Client class.

Just rake db:rollback on your last migration and it should look for the superclass table 'people' and work fine.

Edit : Oops, didn't see you mention CTI, this solution only works for STI.

Upvotes: 1

Shadwell
Shadwell

Reputation: 34774

You're getting an error because you've created a clients table in addition to your persons table. If you have a separate table for each class then the only thing that is inherited is the code and not the contents of the database.

Single Table Inheritance (STI) allows you to add a type column and then instances of the parent class and subclasses will be stored in that single table provided the expected table for the subclass isn't present. You've added that type column but you've also created a clients table. This means that ActiveRecord is expecting you to store Client instances in that table instead of the persons - and when it tries to store a Client there it cannot use the field pesel causing your error.

So, if you want to use STI, then you need to remove your clients table and add an client-specific fields to your persons table.

Alternatively, you can keep your clients table and add the fields from persons that you want to also use for clients to the clients table. This wouldn't then be STI but your Client objects would inherit the methods from Person.

I suspect from your inclusion of the type field that you want to get rid of the clients table.

Upvotes: 1

Related Questions