Today marks the final day to Flatiron's Phase 3. The main topic for Phase 3 was the introduction of Ruby on Rails. This was the most challenging Phase thus far but not without its rewards. One such reward came disguised as a valuable piece of knowledge. This was on how to create groups for an application, dividing a single model into two different usages.
I wanted my users to be able to create a group(faction) that other users could join. Leader vs Joiner. The problem that stumped me was on how to implement leaders & joiners into a single model, Users in my case. To put this into perspective: a faction belongs to a leader, while also having many joiners. Both leaders and joiners can have many factions. theodinproject.com was a wonderful resource on how to implement this idea.
You will have three tables set up like so:
class CivilianFactionRequest < ApplicationRecord belongs_to :requestor, class_name: "Civilian" belongs_to :faction_request, class_name: "CivilianFaction" end
class CivilianFaction < ApplicationRecord belongs_to :owner, :class_name => "Civilian" has_many :civilian_faction_requests, foreign_key: :faction_request_id has_many :requestors, through: :civilian_faction_requests, source: :requestor end
class Civilian < ApplicationRecord has_many :civilian_faction_requests, foreign_key: :requestor_id has_many :civilian_factions, :class_name => "CivilianFaction", :foreign_key => "owner_id" has_many :faction_requests, through: :civilian_faction_requests end
Now to break this down. The CivilianFactionRequest is the join table that will hold the information from the other two tables. This belongs to the specific faction that a user is requesting to join, as well as the user themself.
The lone Faction model is where things start to get tricky. The first line sets the owner upon creation. The second is saying it will have many requests under the specific faction request id. The third is saying the faction will have many requestors(joiners).
The first line describes that the Civilian model(user) will have many faction requests, through the join table, under the requestors id(once they send their request). The second line tells us that the user will have many factions under the owner id. The third tells us that we will have many faction requests as the owner through the join table.
To match these relationships, the migrations will also have a part to play. The civilian migration will be whatever you determine. The important tables are the factions, and the faction_requests(join table)
create_table "civilian_factions", force: :cascade do |t| t.string "name" t.integer "owner_id" t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false end
Civilian Faction Requests:
create_table "civilian_faction_requests", force: :cascade do |t| t.integer "faction_request_id" t.integer "requestor_id" t.boolean "accepted", default: false t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false end
As mentioned previously, the faction will belong to the owner. Through the join table, the faction will have many joiners. To do this, the join table has to take in the faction id as well as the joiner id.
Once this is set up, active record gives you full capabilities to call on chained methods such as
Which will query the faction table for the first faction's requestors. Not to mention the ability to create groups as a leader, and join them as joiners! A tough concept to tackle but super useful in the long run.
Thank you for taking the time to read!