Question

I have a fully working (for some time now) many-to-many relationship in my Rails application.

Instructors has many Schools (through SchoolsToInstructorsAssociations) Schools has many Instructors (through SchoolsToInstructorsAssociations)

At this time, I would like the ability to have an "active state" in addition to simply adding or removing an Instructor from a School or a School from an Instructor.

I want an Instructor to be set as inactive before being removed completely at a later point (or reactivated).

My first thought was to add an 'active' boolean to the relationship model (SchoolsToInstructorsAssociations), but there's no simple way to access this attribute to update or query it).

My second thought was to simply create another relationship model with the 'active' attribute, but it's redundant and something extra I have to track.

Maybe a custom many-to-many module? Create a SchoolsToInstructorsAssociations controller?

class Instructor < ActiveRecord::Base
  has_many :schools_to_instructors_association
  has_many :schools, :through => :schools_to_instructors_association
end

class School < ActiveRecord::Base
  has_many :schools_to_instructors_association
  has_many :instructors, :through => :schools_to_instructors_association
end

class SchoolsToInstructorsAssociation < ActiveRecord::Base
  belongs_to :user
  belongs_to :school
end

I also plan to create a history record each time an instructors 'active' state changes or an instructor is removed or added to a school. Not asking how to do this, but wondering if it could be used to track an instructors 'active' state.

class SchoolsController < ApplicationController
  def instructors_index
    @school = School.find(params[:id])
    instructors = find_instructors
    @active_instructors = instructors[0]
    @inactive_instructors = instructors[1]

    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @schools }
    end
  end

  private

  def find_instructors
    active = []; inactive = []
    @school.instructors.each do |s|
      if SchoolsToInstructorsAssociationRecord.where(user_id: s, school_id: @school)[0].active?
        active << s
      else
        inactive << s
      end
      return [active, inactive]
    end
  end
end

class SchoolsToInstructorsAssociationRecord < ActiveRecord::Base
  default_scope order('created_at DESC')
  attr_accessor :user_id, :school_id, schools_to_instructors_association_id, :active
end      
Was it helpful?

Solution

Sounds like you can accomplish what you're trying to do with scopes. Add a boolean column for 'active' as you described for the 'Instructor' class, then you can add scopes for it:

class Instructor < ActiveRecord::Base
  ...
  scope :active, -> { where(active: true) }
  scope :inactive, -> { where(active: false) }
  ...
end

Then for a given School, you can get the active (or inactive) instructors for that school:

@school.instructors.active
=> SELECT "instructors".* FROM "instructors" WHERE "instructors"."school_id" = <id> AND "instructors"."active" = 't'

If you wanted to do some operations on all the inactive instructors (like destroy them, as an example), you could do:

Instructor.inactive.map(&:destroy)

And you can of course write whatever custom methods you want for the Instructor or School classes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top