Search code examples
ruby-on-railspolymorphismpolymorphic-associationssingle-table-inheritancesti

Rails STI vs Polymorphic vs Neither


I have a Users class in my rails app. I need two types of users, 1) Players, 2) Managers. Users will all log in using Devise and have same basic user fields. I will have a League model. What is the best way to model this? STI doesn't seem quite right but not sure if Polymorphic works either since if both Manager < User && Player < User. The only real role a manager will have will be admin roles such as adding/removing players from leagues, setting up schedules etc.

class League < ActiveRecord::Base
  has_one :manager
  has_many :players

end

class Match < ActiveRecord::Base
  has_and_belongs_to_many :players
  belongs_to :league
end

class User < ActiveRecord::Base
  has_and_belongs_to_many :matches
  has_and_belongs_to_many :leagues
end

class Player < User
  has_and_belongs_to_many :leagues
  has_and_belongs_to_many :matches
end

class Manager < User
  has_many :leagues
end

Any suggestions for the best way to set this up are greatly appreciated! Using STI for players ActiveRecord is looking for Player table for the join but it doesn't exist.


Solution

  • STI can work for this, but since the difference between the types of users is basically a flag that says a user is an admin, you just need something on a user to check whether they are allowed certain actions. Roles can be either exclusive or inclusive (so that a user can be both a Player and a Manager), but once set up you can shape the interface around the capabilities a user has:

    <% if @user.has_role?('manager') %>
      <%= render 'manager_fields' # or manager_page, etc. %>
    <% end %>
    

    How you handle this in the controller depends on how you implement the roles, either via gems like Pundit, CanCanCan, etc. or through explicit checks in something you write yourself. The gems will give you helper methods to reduce the amount of typing involved in views and a more declarative syntax on the back end.