Math Newb
Math Newb

Reputation: 13

Rails belongs_to and has_many of the same model

I am trying to create a database schema in rails between two models Users and Circles. A circle is a user defined group known only to the user who created this. The Circle contains other users that the user selected to be in that circle and a circle name.

So my solution is the following:

  1. Users model: has_many: Circles
  2. Circles model: belongs_to: User, has_many: Users

I know that there exists a has_many through method but I don't know if that's necessary for my case.

Upvotes: 1

Views: 358

Answers (1)

max
max

Reputation: 102164

You actually need two different associations. The first is a one-to-many association. The lazy way to set it up would be:

class Circle < ApplicationRecord
  belongs_to :user
end


class User < ApplicationRecord
  has_many :circles
end

This links users to circles through the foreign key column user_id on circles. Buts its pretty ambigous - what does user.circles mean? Is it circles a user has created or those he is a member of? Better be a bit more explicit even if it takes some configuration:

class RenameUserToCreator < ActiveRecord::Migration[6.0]
  def change
    rename_column :circles, :user_id, :creator_id
  end
end

# rails g model circle 
class Circle < ApplicationRecord
  belongs_to :creator, class_name: 'User'
end


class User < ApplicationRecord
  has_many :created_circles, 
    class_name: 'Circle',
    foreign_key: :creator_id
end

Next you want to add members to a circle. This is a many-to-many association and can be done using has_many through: or has_or_belongs_to_many. Both use a join table but has_or_belongs_to_many does not have a model and is very limited in its actual usefulness. When naming join tables the lazy conventions is to just use an amalgamation of a & b - CircleUser but do use a better name if you can think of one that fits the domain.

class Circle
  belongs_to :creator, class_name: 'User'
  has_many :memberships
  has_many :users, through: :memberships
end

# rails g model membership user:belongs_to circle:belongs_to
class Membership
  belongs_to :user
  belongs_to :circle
end

class User
  has_many :created_circles, 
    class_name: 'Circle',
    foreign_key: :creator_id
  has_many :memberships
  has_many :circles, through: :memberships
end

One thing to bear in mind is that each association MUST have a unique name. If we didn't go through that previous step and wrote:

class User
  has_many :circles
  has_many :memberships
  has_many :circles, through: :memberships
end

The latter association would just clobber the previous association.

Upvotes: 1

Related Questions