ruby-on-railsactiverecordforeign-keysrelationshiptable-relationships

Rails Complex Active Record Relationship


I have a complex active record relationship in mind, and was wondering how exactly I would accomplish it. In essence:

A User can create a Board. A user can then add other users to that board for collaborative editing. Added users form a Team. Each added User has a Role in each board, (Admin, Editor, Viewer).

I was thinking of setting it up this way:

The role part has been confusing me. Do I have to set up a TeamUser model which has many Roles, or does each User have many Roles which belong to a Board? Does a Role even have to be it's own model?

What is the most effective way to accomplish my goal?


Solution

  • If a user could belong to many teams and could have many roles, logic could be something like:

    You need a join table to supply the N-to-N relationship between User and Board model. But the thing is, when you add a user to a board, you give them a role in that participation. It's a good place to hold role info in that participation. So our UsersBoards join-table transform into the Participation model (Or whatever you like to call it). Our participation model now holds the user, board and role info (All of them is foreign-key).

    I didn't exactly understand the purpose of the Team model but I think it's easy to add a user to a team when it's necessary. It will not hurt to our logic.

    Also, if you don't plan to add more features in the future, role can be an enum too.

    class User < ApplicationRecord
      has_many :participations
      has_many :boards, through: :participations
    end
    
    class Board < ApplicationRecord
      has_many :participations
      has_many :users, through: :participations
    end
    
    class Participation < ApplicationRecord
      belongs_to :user
      belongs_to :board
      enum role: [ :admin, :editor, :viewer ]
    end
    
    user = User.first
    user.participations.first.board #Board
    user.participations.first.admin? #true
    user.boards
    

    And you can add helper methods or delegate to models for shortening the query.