I recently found a problem in a Rails app related to duplicate entries in a join table. The app is educational, and includes models for Students and Exercises. The join table keeps track of which exercises have been assigned to which students. It doesn't make sense for an exercise to be assigned to a student more than once (i.e. duplicate entries in the join table shouldn't be allowed).
I partially fixed the problem by adding a uniqueness validation to the join table (see the last line of code, below). This validation will prevent any new duplicate entries from being created in the future. I'm still faced with the problem, however, of addressing the existing duplicates in the table.
Is there a way to run the new validation against the entire existing database, to retrieve all the records that are no longer valid?
class Student < ActiveRecord::Base
has_many :student_exercise_assignments
has_many :exercises, :through => :student_exercise_assignments
end
class Exercise < ActiveRecord::Base
has_many :student_exercise_assignments
has_many :students, :through => :student_exercise_assignments
end
class StudentExerciseAssignment < ActiveRecord::Base
belongs_to :student
belongs_to :exercise
validates :exercise_id, :uniqueness => { :scope => :student_id, :message => "An exercise can only be assigned to a student once" }
UPDATE
Shioyama's answer below gives exactly the information I was looking for. Being a Rails newbie, though, I was a bit confused by his use of &
in &:invalid?
. If anyone needs an primer of the &
operator in Ruby, there's a good one here.
How about just:
invalid_assignments = StudentExerciseAssignment.select(&:invalid?)
This will select all assignments which return true when called with the invalid?
method. You can then do whatever you need to do to fix them.
As a side note, I would also suggest adding a uniqueness constraint to your database. See this answer for reasons why: Rails: Validation in model vs migration
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With