Search code examples
ruby-on-railsrails-activerecordhas-and-belongs-to-manyuser-accounts

group creator transfered to other user if group creator leaves group


First question: I have a group model that belongs_to :creator, :class_name => "User" and if the creator leaves I want someone else in the group to become the "creator". How would I do this?

As a second question, I would also like to give the leaving creator to choose a new creator when leaving, or let it be automatically assigned.

as of right now these are what my models look like:

class Group < ActiveRecord::Base

  belongs_to :creator, :class_name => "User"

  has_many :members, :through => :memberships
  has_many :memberships, :foreign_key => "new_group_id"

and my User model:

class User < ActiveRecord::Base

  has_many :groups, foreign_key: :creator_id

  has_many :memberships, foreign_key: :member_id
  has_many :new_groups, through: :memberships

As a third question, I would like the group to be destroyed when the creator leaves. How can I set up this kind of relation?


Solution

  • These are 3 questions, and the first two are quite open, so I'd try to answer all of them in order making some assumptions down the road.

    First question

    This depends on what do you want the behavior for choosing a new creator to be. Do you want it to be automatically assigned from the current members? Do you want to give other members to have the change to auto-assign themselves as creator? In the latter you need to provide your members a full UI (routes, controllers, views) for that purpose, so I'll show you how would I code the first option.

    First, I'd encapsulate the group leaving logic into its own method on the Group model, that we'll use in the controller for this purpose. On Group we define the logic for assigning as new creator. The logic here will be to pass the method a new_creator if we have it, or default to the first of the members if not given.

    class Group < ActiveRecord::Base
      def reassign(new_creator = nil)
        new_creator ||= members.first
    
        if new_creator
          self.creator = new_creator
          save
        else
          false
        end
      end
    end
    

    As an alternative approach, you can move this logic into an Observer (or any alternative) that will observe on Group model for the attribute creator_id to be nulled.

    Second question

    This one will involve a full UI that you'll need to figure out yourself according to your specifications. In short, I'd create a new action in your GroupsController for members to leave groups like this:

    # config/routes.rb
    resources :groups do
      member do 
        get :leave
        patch :reassign
      end
    end
    
    # app/controllers/groups_controller.rb
    class GroupsController < ApplicationController
      def leave
        @group = Group.find(params[:id])
      end
    
      def reassign
        @group = Group.find(params[:id])
        if @group.reassign(params[:new_creator_id])
          redirect_to my_fancy_path
        else
          render :leave
        end 
      end
    end
    

    In your views you'll have your form_for @group with the new member candidates (possible with a select_tag :new_creator_id) and the rest of your UI as you prefer.

    Third question

    This is the easiest. You just define your association like this and you'll get all User groups destroyed after the user is deleted.

    class User < ActiveRecord::Base
      has_many :groups, foreign_key: :creator_id, dependent: :destroy
    end