4

Scenario:

I have a habtm relationship and would like to determine if children in one direction have been added or deleted. I'm trying to use callbacks but find i don't have a record of changes to the children. Is there something like course.students.changed?


Using:

  • Rails 3.0.3
  • Ruby 1.9.2p0

Tables:

students - id, first_name, last_name
courses - id, name, location
courses_students - course_id, student_id


Models:

class Course
  # Callbacks
  before_save :student_maintenance

  # Relationships
  has_and_belongs_to_many :students

  protected
  def student_maintenance
    # I want to do something like
    students.changed?
      students.changes.each do |student|
        if marked_for_deletion
          # do something
        elsif marked_for_addition
          # do something else
        end
      end
    end
  end
end

class Student
  # Relationships
  has_and_belongs_to_many :courses
end
Becky
  • 207
  • 2
  • 12

2 Answers2

2

If you want to capture when a student has been added or removed from a course, why not use a class for the join table *courses_students*? Since that's the place where an entry will be actually created or destroyed you could easily use after_create/after_destroy callbacks in there.

polarblau
  • 17,649
  • 7
  • 63
  • 84
  • Does that mean I have to change the relationships? I.e Course has_many :courses_students, Course_Student belongs_to :courses belongs_to :students, Student has_many :courses_students. Did I pluralize correctly? – Becky Jan 06 '11 at 21:16
  • You would probably change the "has_and_belongs_to_many" relationship to a "has_many through" ( http://guides.rubyonrails.org/association_basics.html#the-has_many-through-association ). Something along the lines of "Student has_many :course, :through => :courses_students" and "Course has_many :students, :through => :courses_students" while it would be probably nice to have a more descriptive join model name. Your join model "Class CoursesStudents" would then contain "belongs_to :student" and "belongs_to :course" and your callbacks. Do you know what I mean? – polarblau Jan 06 '11 at 21:30
  • So ditch the habtm for has_many through. I think I get it. I'll try it out and mark this correct if it works out for me. – Becky Jan 06 '11 at 21:52
  • @Becky You got a solution other than HABTM? – loganathan Feb 17 '17 at 06:23
  • @Becky is that really necessary? Change the model. There surely must be a less invasive way to deal with this. – Sebastialonso Oct 17 '17 at 20:07
0

Similar to polarblau's answer -- but a tad more explanation, I hope:

In textual, UML terms, the relationship might be this:

Course ------*-> Student

Read: A Course has 0 to Many Students

You can add and remove students from the association at will.

However, you are interested in knowing more about the association, that is, when the student was added or dropped from the course. This "extra" information about an association leads to discovering you need another class, a.k.a. "Association Class."

So now you would insert that class in between your existing classes as so, taking the liberty to call it a "Registration":

Course ------*->Registration------1->Student

Read: A Course has 0 to Many Registration. Each Registration must have exactly 1 Student.

The Registration class might look like this:

+--------------+
| Registration |
+--------------|
| student      |
| time_added   |
| time_dropped |
+--------------+

So you can easily get a list of current students for a course (where time_dropped is nil). Or a list of dropped students (where time_dropped is not nil).

Jon Kern
  • 3,186
  • 32
  • 34