I see the following options here.
1. Single table inheritance (STI)
Just dump all the fields in one table, and make class Boxer < User, class Footballer < User.
Pros: Simplicity of implementation.
Cons: Table become bloated. Fields are shared, i.e. your footballer will have weight and other fields and vice versa.
2. Moving base information to another table
That's the option you already outlined.
Pros: Clean tables, proper separation of fields.
Cons: Complex implementation. You will have to ensure that there is always one and only one basic profile for each instance. So you will have to pay attention to :delete_all/:destroy_all options of association macroses, and maybe before_create/after_destroy as well.
Here is an example on how to organize that in your code:
# models
class Profile < ActiveRecord::Base
# you need to create
# t.integer :user_id
# t.string :user_type
# in a migration for 'profiles' table
belongs_to :user, polymorphic: true
end
class User < ActiveRecord::Base
# This will disable STI
self.abstract_class = true
has_one :profile, as: :user, dependent: :destroy
def some_common_user_method
# ...
end
def pick_profile
self.profile && return self.profile
if self.persisted?
self.create_profile
else
self.build_profile
end
end
end
class Footballer < User
end
# controllers
class UsersController < ApplicationController
before_action :set_klass
before_action :set_user, except: [:index, :create]
# ...
def create
@user = @klass.new
@user.pick_profile
# etc...
end
def destroy
@user.destroy
end
private
def set_klass
# white-list search for class
@klass = User.descendants.find{|k| k == params[:type].camelize.constantize}
end
def set_user
@user = @klass.find(params[:id])
end
end
# routes
# for URLs like /users/1?type=footballer
resources :users
# for URLs like /users/footballer/1
resources :users, path_prefix: '/users/:type'
3. Adding a serialized field
Just add details field with JSON/YAML of specific sportsmen details, and have common fields as separate DB fields.
Pros: Simplicity of implementation. Database structure stays simple as well.
Cons: You won't be able to make effective queries on specific sportsman's fields, i.e. you will need to fetch each record to know its details.
4. Using Postgresql-specific serialized columns
Same as above, only without "cons" part. You will be able to make efficient queries on serialized data.
Cons: You will need to learn how to use that fields and query them. Not possible with MySQL.