Building a Rails API to Track Student Progress
Christopher Ninman
Posted on April 8, 2022
What is the most difficult thing about being a teacher? Actually, that's a trick question. Everything is difficult, hence, my switch to becoming a software developer. But one of those difficult teacher tasks is gathering data, as a means to guide your instruction, along with a way to show parents that you know their children well. As a teacher, I was always hoping to find the balance of a fun, engaging app that actually taught my students, while giving me some information about them after they finished.
As a 3rd grade teacher, I tried to make sure every one of my students was able to walk away with the ability to recite their multiplication facts in no time. But it was difficult to keep track of what each of them knew. So, after a switch to programming, I began my quest to create an application that could track students' knowledge of the times tables.
The Database
I'll be covering the set up of the database using Ruby on Rails and ActiveRecord. Setting up the frontend is a whole other story, but what we're really after here, and what a teaching application should create, is data.
The structure of a classroom lends itself easily to being created using Active Record associations. Here is how we can set up our models:
Teacher model - has_many :classrooms, has_many: students, through: :classrooms
Classroom model - has_many :students, belongs_to: teacher
Student model - belongs_to: classroom
As a teacher, sometimes you need data on individual students, other times you'll need data on your whole classroom. Think about how you'll want to access the data throughout whatever app you have planned.
If you want the teacher to have simple access to all of their students, you can include that association.
class TeacherSerializer < ActiveModel::Serializer
attributes :id, :username, :is_teacher
has_many :classrooms
has_many :students, through: :classrooms
end
With this set up through your ActiveRecord associations, an array of students will now be available at the first level of your data that you fetch, along with all of the data they hold. Though you can serialize their data and return their classroom_id, they will not be nested in the second level within a classroom. You'll need to handle that logic on the front end.
Another option is to take away the has_many :students, through: :classrooms association, and instead serialize your classroom data to include the students.
class TeacherSerializer < ActiveModel::Serializer
attributes :id, :username, :is_teacher
has_many :classrooms
end
class ClassroomSerializer < ActiveModel::Serializer
belongs_to :teacher
has_many :students
attributes :id, :classroom_name, :students
Create a Problem model
In my case, building an app to track student knowledge of the times tables, I created a Problem model, with 100 entries, each one containing a problem (string: "6 x 7"), and an answer (integer: 42).
In order to create student data to track, I needed to create a joins table through my ActiveRecord associations to keep tabs on a student's progress.
Create a Mastery model
The Mastery model is a table created to house a student's data on each of the entries in the Problem model. (You could alternately think of this as a Quiz model, rather than one single problem.)
Now to set up the joins the table:
class Problem < ApplicationRecord
has_many :masteries
has_many :students, through: :masteries
end
class Student < ApplicationRecord
has_many :masteries
has_many :problems, through: :masteries
end
class Mastery < ApplicationRecord
belongs_to :student
belongs_to :problem
end
Each time a student takes a quiz, you can create a new instance of a Mastery (or Quiz), giving it attributes such as :times_answered, :times_correct, :mastery_level, or custom methods, such as :mastery_percentage. And thanks to our associations, each instance of a Mastery will also have a :student_id and a :problem_id.
In the case of the multiplication tables, students will review facts multiple times, so their scores can be updated regularly to reflect how many times each fact was answered and how many times it was answered correctly.
Customizing our Data
Now comes the fun part. What sort of data do we want our teachers to have access to? We can build custom methods to return whatever we think will be valuable information about the students.
class Student < Application Record
def mastery_percentage
self.masteries.average(:total_score).to_f
end
def difficult_facts
self.masteries.where("total_score" < ?", 20)
end
end
In the first method, we make a call to the database, which will return to us a method for each student, searching through each of the student's Masteries, and returning the average of all of them. In the second custom method, we're returning a custom list that searches through each student's masteries and finds all cases where their :total_score is less than our chosen number.
Just make sure you add your custom defined method into your Student serializer.
class StudentSerializer < ActiveModel::Serializer
attributes :id, :username, :mastery_percentage,
:difficult_facts, :classroom_id, :masteries,
belongs_to :classroom
has_many :masteries
end
Teachers deserve all the help they can get. Educational apps with well thought out databases are just what those teachers are looking for.
Photo by John Schnobrich on Unsplash
Posted on April 8, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.