Search code examples
ruby-on-railsmodeldeviseassociationshas-many-through

Complex Rails Models/Associations


I'm building an assigning system for referees.

Issue I asked this question previously/slightly different but have run into trouble again. I have 5 models essentially that need to be linked together and I can't find a resource online to specify/guide me to the solution for more than 3 tables to be joined. I think I have it nailed down for the meantime and I can pull what I need to in the console but it just seems all over the place.

Models in plain English:

  1. League - Devise user who can log in and upload a schedule(create games) through a form
  2. Assignor - Devise user who then takes that schedule and assigns referees to the games
  3. Referee - Devise user who gets assigned to games
  4. Game - created by League (contains teams,venue, referee crew assigned)
  5. Assignment - created when League creates a game

My models/associations are:

class Assignor < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  has_many :games
  has_many :referees
  has_many :assignments, through: :games
  belongs_to :league
end

class Referee < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  belongs_to :assignor
  has_and_belongs_to_many :games
  has_many :assignments, through: :games
end

class Game < ApplicationRecord
  belongs_to :league
  belongs_to :assignor
  has_and_belongs_to_many :referees
  has_one :assignment
end

class Assignment < ApplicationRecord
  belongs_to :assignor
  belongs_to :referee
  belongs_to :game
end

class League < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  has_one :assignor
  has_many :games
end

EDIT - Actual Trouble I've Encountered

For an Assignment to have more than 1 referee, do I need to change the table to reflect that? Right now the table is as follows and allows one referee but I need up to 4 on one Assignment:

create_table "assignments", force: :cascade do |t|
    t.integer "assignor_id", null: false
    t.integer "referee_id", null: false
    t.integer "game_id", null: false
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["assignor_id"], name: "index_assignments_on_assignor_id"
    t.index ["game_id"], name: "index_assignments_on_game_id"
    t.index ["referee_id"], name: "index_assignments_on_referee_id"
  end

How do I model it so that the table looks like:

reate_table "assignments", force: :cascade do |t|
    t.integer "assignor_id", null: false
    t.integer "game_id", null: false
    t.integer "center_referee", null: false
    t.integer "assistant_referee_one", null: false
    t.integer "assistant_referee_two", null: false
    t.integer "fourth_official", null: false
  end

Would it be better to create another model/replace another model and name it "crew_referee" to associate referees to games?

End Goal I want to be able to have a League create a schedule composed of Games that an Assignor assigns Referees to through an Assignment.

My thinking was that essentially I want to be able to have a User log in and see their respective Games and Assignments.


Solution

  • A possible solution would be to allow the user to create multiple assignments per game, then he could assign multiple referees, each with a different role.

    To reflect the role / type of the referee, you could add another column to the assignment table which holds the information about the assignment type (center, assistant, ...)

    If you really want to have just one assignment per game which holds the references to 4 referees, you could do:

    class CreateAssignments < ActiveRecord::Migration[6.1]
      def change
        create_table :assignments do |t|
          t.references :assignor, null: false, foreign_key: true
          t.references :game, null: false, foreign_key: true
          t.references :center_referee, null: false, foreign_key: { to_table: :referees }
          t.references :assistant_referee_one, null: false, foreign_key: { to_table: :referees }
          t.references :assistant_referee_two, null: false, foreign_key: { to_table: :referees }
          t.references :fourth_official, null: false, foreign_key: { to_table: :referees }
          t.timestamps
        end
      end 
    end
    

    To make a referee accessible via the Assignment you would put the following in the Assignment model:

    belongs_to :center_referee, class_name: 'Referee', foreign_key: 'center_referee_id'
    belongs_to :assistant_referee_one, class_name: 'Referee', foreign_key: 'assistant_referee_one_id'
    ...