CSC/ECE 517 Spring 2025 - E2513. Reimplement sign up topic.rb as project topic.rb
About Expertiza
Expertiza is an open source project based on Ruby-on-Rails framework which allows instructors to create or edit assignments with topic lists for students to choose from. Students can form teams in Expertiza to work on the assignments together. Students can peer review other students’ works and also give feedback to help their peers improve. Students can also view their grades for the projects once the instructors have graded them.
Problem Statement
The original SignUpTopic class in Expertiza manages topics within assignments, handling slot availability, team signups, and waitlist management. Our task was to redesign this functionality in the reimplementation_backend repository while improving code quality and maintainability.
The reimplementation project consists of:
- The SignUpTopic class should be reimplemented as ProjectTopic.
- Generate migration files to create tables for storing ProjectTopics and SignedUpTeams.
- This class should include a method to sign a team up for a topic.
- It should include functionality to handle the case when a team drops a topic, ensuring that the topic is assigned to the team that has been waiting the longest. A team may drop a topic through the UI, or when the last member leaves a team with an assigned topic, the topic is automatically released.
- It should include a method that returns the AssignmentTeams signed up for a topic.
- It should include a method to retrieve its current number of available slots for team sign-ups and modify that number.
- The methods find_team_participants, find_team_users, and find_user_signup_topics from the SignedUpTeam model are unclear and difficult to maintain. They should be reimplemented with clearly defined responsibilities and enhanced readability.
- find_team_participants and find_team_users have overlapping purposes. We need to clarify each method’s distinct role or merge their functionalities if appropriate.
- find_user_signup_topics needs clearer logic for retrieving topics associated with a user's team, improving readability and efficiency.
Previous Implementation
Models
1. SignUpTopic Model
The original implementation of SignUpTopic model includes basic associations but lacks the required functionality for managing topic signups and waitlists. The model establishes relationships with signed_up_teams, teams, assignment_questionnaires, and due_dates, and belongs to an assignment.
2. SignUpTeam Model
The SignedUpTeam model defines the relationship between teams and topics. It includes scopes for confirmed and waitlisted teams, and belongs to both project_topic and team. The model implements basic methods for signing up teams for topics and removing team signups.
Controller
1. ProjectTopicsController
The ProjectTopicsController handles CRUD operations for project topics. It includes methods for retrieving topics by assignment_id and optional topic_ids, creating new topics, updating existing topics, showing topic details, and deleting topics. The controller implements proper error handling and returns appropriate status codes and messages for different scenarios. It also includes parameter validation to ensure that required parameters are provided.
2. SignedUpTeamsController
The SignedUpTeamsController manages the relationship between teams and topics. It implements methods for retrieving signed-up teams for a topic, updating signed-up team information, signing up teams for topics, signing up students for topics, and removing teams from topics. The controller includes methods like sign_up and sign_up_student that handle the process of signing up teams and students for topics, respectively. It also includes a destroy method for removing teams from topics.
Drawbacks in Previous Implementations
The original implementation of the topic signup system in the Expertiza repository has several significant drawbacks that our reimplementation aims to address.
The ProjectTopic model is overly simplistic, containing only basic association definitions without the necessary methods for managing critical features like slot availability, waitlists, team drops, and topic reassignment. This lack of functionality makes it impossible for the system to effectively handle topic signups, which are a core feature of the platform.
Similarly, the SignedUpTeam model includes basic scopes and validations but fails to provide robust waitlist management or topic reassignment capabilities. While it has methods for signing up teams and removing team signups, these are incomplete and lack the complex logic needed for effective waitlist handling.
Additionally, there is a disconnect between the controllers and models. Many controller methods rely on functionality that does not exist in the models, resulting in a fragmented system incapable of supporting a seamless topic signup workflow.
Furthermore, the methods find_team_participants and find_team_users in the SignedUpTeam model have overlapping purposes, creating confusion about their distinct roles. This overlap necessitates either a clear separation of responsibilities or merging their functionalities to streamline their usage.
Lastly, the find_user_signup_topics method lacks clear logic for retrieving topics associated with a user's team. The current implementation is inefficient and difficult to read due to its reliance on complex SQL joins. This method needs to be rewritten using ActiveRecord associations to improve both readability and query performance.
These shortcomings highlight the need for a comprehensive reimplementation to improve clarity, modularity, and maintainability while ensuring that the system meets its functional requirements effectively.
Design
UML Diagram
The UML diagram showcases the reimplemented ProjectTopic and SignedUpTeam models that the team worked on, and lists the reimplemented methods that were done in the ProjectTopic model during Project 3 along with the ones done in the SignedUpTeam model during Project 4.
Flowchart
The flowchart illustrates the workflow and interactions involved in team sign-up management for project topics within the Expertiza system. It clearly highlights both functionalities implemented in Project 3 and Project 4 in the ProjectTopic and SignedUpTeam models:
- User Access and Team Signup:
- Users initially access the available project topics.
- Teams then sign up for their preferred topics via the signup_team method.
- Slot Availability Check:
- Upon signup, the system checks if topic slots are available (available_slots).
- If slots are available, the team is added directly as a confirmed participant.
- If no slots remain, the team is placed on a waitlist.
- Identifying Team Participants:
- The newly implemented method find_team_participants would retrieve users belonging to a specific team, facilitating clearer participant management.
- Team Drop and Waitlist Promotion:
- Teams can drop topics using the drop_team method.
- If a confirmed team drops a topic, the next waitlisted team is automatically promoted to a confirmed status.
- Enhanced User and Topic Tracking:
- find_team_users method would identify all users associated with teams signed up for a particular topic, enhancing transparency in team-topic relationships.
- find_user_signup_topics method would provide an efficient way for users to view all topics their teams have signed up for, improving user experience.
Solution
To address these issues, our reimplementation focuses on:
- We have implemented a more robust ProjectTopic model with methods for checking slot availability, managing waitlists, handling team drops, and reassigning topics. This includes methods like slots_available?, available_slots, update_max_choosers, promote_waitlisted_teams, and sign_up_team that provide the core functionality needed for topic management.
- Our implementation also includes a comprehensive waitlist system that automatically promotes teams from the waitlist when slots become available, either through increased capacity or when teams drop topics. This ensures fair and efficient allocation of topic slots.
- We have also implemented proper validation and error handling throughout the system to ensure that users receive clear feedback when operations fail and to prevent data inconsistencies.
- Furthermore, we have added RSpec tests for all functionality to ensure that the system works as expected and handles edge cases properly. This will help prevent regressions as the codebase evolves.
- We have improved the method logic in find_team_participants by eliminating redundant nested queries, clearly retrieving team participants using direct ActiveRecord associations, thus enhancing readability and performance.
- We have simplified the query logic in find_team_users by explicitly using ActiveRecord associations to directly fetch distinct teams and associated users, significantly improving maintainability and query efficiency.
- We have rewritten the complex manual SQL joins in find_user_signup_topics into clear ActiveRecord associations, providing straightforward logic for fetching relevant signup topics, optimizing both readability and query execution.
Code Improvements
1. The original signup_team method manually checked for existing team registrations and handled waitlist logic with conditional checks. We introduced ActiveRecord::Base.transaction to ensure atomicity during signup.Replaced manual checks with signed_up_teams.exists? for cleaner validation. Separated waitlist removal into a dedicated method (remove_from_waitlist).
def signup_team(team) return false if signed_up_teams.exists?(team: team) ActiveRecord::Base.transaction do signed_up_team = signed_up_teams.create!( team: team, is_waitlisted: !slot_available? ) remove_from_waitlist(team) unless signed_up_team.is_waitlisted? true end rescue ActiveRecord::RecordInvalid false end
2. The original drop_team_from_topic method manually managed waitlist promotion and lacked encapsulation. We introduced promote_waitlisted_team to automatically promote the next waitlisted team. Separated concerns into private methods for clarity.
def drop_team(team) signed_up_team = signed_up_teams.find_by(team: team) return unless signed_up_team team_confirmed = !signed_up_team.is_waitlisted? signed_up_team.destroy! promote_waitlisted_team if team_confirmed end
3. The original code used raw SQL queries for filtering confirmed/waitlisted teams. We added scopes confirmed and waitlisted to SignedUpTeam for reusable queries.
scope :confirmed, -> { where(is_waitlisted: false) } scope :waitlisted, -> { where(is_waitlisted: true) }
4. The original current_available_slots method calculated slots using raw SQL counts. Replaced with a memoized count using scopes.
def available_slots max_choosers - confirmed_teams_count end def slot_available? available_slots.positive? end def promote_waitlisted_team next_team = waitlisted_teams.first return unless next_team signed_up_teams.find_by(team: next_team)&.update!(is_waitlisted: false) remove_from_waitlist(next_team) end
5. The original find_team_participants method utilized complex nested loops and multiple repetitive queries. Our improved approach takes a team_id as input, attempts to find the corresponding team, and returns an array of users associated with that team. If the team does not exist, it returns an empty array. This provides a more straightforward way to list all members of a given team, which is essential for participant management and display.
def self.find_team_participants(team_id) team = Team.find_by(id: team_id) return [] unless team team.users.to_a end
6. The original find_team_users method contained unclear, hardcoded SQL queries. Our improved approach looks up a SignedUpTeam record using the provided team_id. If found, it retrieves the users belonging to the associated team. If there is no such signup, it returns an empty array. This is useful for identifying which users are part of a team that has signed up for a specific topic.
def self.find_team_users(team_id) signed_up_team = SignedUpTeam.find_by(team_id: team_id) return [] unless signed_up_team signed_up_team.team.try(:users).to_a end
7. The original find_user_signup_topics method used complicated raw SQL joins. Our improved approach first locates the user by user_id. If the user exists, it gathers all the team IDs the user is a member of. It then queries the ProjectTopic model, joining through SignedUpTeam, to find all topics for which any of the user’s teams are signed up. The result is a distinct list of ProjectTopic objects. If the user does not exist, it returns an empty array. This method allows users to easily see all topics their teams are involved with.
def self.find_user_signup_topics(user_id) user = User.find_by(id: user_id) return [] unless user ProjectTopic.joins(:signed_up_teams) .where(signed_up_teams: { team_id: user.teams.pluck(:id) }) .distinct.to_a end
RSpec Testing
The current version of Expertiza did not have any tests for the ProjectTopic and SignedUpTeam models, so we introduced a comprehensive set of RSpec tests for the ProjectTopic and SignedUpTeam models to validate topic signup workflows, team management, and RESTful API compliance. These tests ensure atomicity for database operations, edge-case handling for capacity limits, and adherence to business logic for waitlist prioritization. By mocking associations and leveraging Rails’ transactional fixtures and factories, we achieved deterministic test outcomes across 57 scenarios.
- Team Signup/Drop Workflows: We test all possible scenarios including successful signups, waitlist handling, and team removal cases. This includes verifying that:
- Teams are properly assigned to available slots
- Waitlisted teams are automatically promoted when a slot open up
- Duplicate signups are prevented
- Slot Availability Calculations:Tests confirm the system correctly calculates and updates available slots when:
- Teams join or leave a topic
- Topics reach maximum capacity
- Waitlisted teams are promoted
- Waitlist Ordering:We validate the FIFO (First-In-First-Out) processing of waitlisted teams by:
- Tracking creation timestamps
- Verifying promotion order matches signup sequence
- Ensuring fairness in team assignments
- ProjectTopic ↔ Team Relationships:We verify the many-to-many association through the SignedUpTeam join model works correctly by testing:
- Proper creation and destruction of join records
- Cascading deletions when topics or teams are removed
- Maintenance of referential integrity
- Join Record Validations:Tests confirm the SignedUpTeam model:
- Enforces uniqueness constraints (preventing duplicate signups)
- Validates presence of required associations
- Maintains proper waitlist status flags
- CRUD Operation Mapping:We verify all standard endpoints are properly routed:
- GET /api/v1/project_topics → index action
- POST /api/v1/project_topics → create action
- GET/PUT/PATCH/DELETE /api/v1/project_topics/:id → respective actions
Routing Tests
The project_topics_routing_spec.rb file tests the RESTful routing for the ProjectTopicsController:
describe "routing" do it "routes to #index" do expect(get: "/api/v1/project_topics").to route_to("api/v1/project_topics#index") end it "routes to #show" do expect(get: "/api/v1/project_topics/1").to route_to("api/v1/project_topics#show", id: "1") end it "routes to #create" do expect(post: "/api/v1/project_topics").to route_to("api/v1/project_topics#create") end it "routes to #update via PUT" do expect(put: "/api/v1/project_topics/1").to route_to("api/v1/project_topics#update", id: "1") end it "routes to #update via PATCH" do expect(patch: "/api/v1/project_topics/1").to route_to("api/v1/project_topics#update", id: "1") end it "routes to #destroy" do expect(delete: "/api/v1/project_topics/1").to route_to("api/v1/project_topics#destroy", id: "1") end end
These tests confirm that:
- All standard RESTful routes are properly configured
- The routes map to the correct controller actions
- The routes include the proper namespacing
ProjectTopic Model Tests
The project_topic_spec.rb file tests the core functionality of the ProjectTopic model:
Team Signup Process
describe '#signup_team' do context 'when slots are available' do it 'adds team as confirmed' do expect(project_topic.signup_team(team)).to be true expect(project_topic.confirmed_teams).to include(team) end it 'removes team from waitlist' do other_topic = ProjectTopic.create!(topic_name: "Other Topic", assignment: assignment, max_choosers: 1) other_topic.signup_team(team) project_topic.signup_team(team) expect(other_topic.reload.waitlisted_teams).not_to include(team) end end end
This test verifies that:
- Teams are properly assigned to available slots
- When a team signs up for a new topic, it's automatically removed from waitlists of other topics
Waitlist Management
context 'when slots are full' do before do 2.times do |n| t = Team.create!(assignment: assignment) project_topic.signup_team(t) end end it 'adds team to waitlist' do new_team = Team.create!(assignment: assignment) expect(project_topic.signup_team(new_team)).to be true expect(project_topic.waitlisted_teams).to include(new_team) end end
This test verifies that:
- When a topic reaches maximum capacity, new teams are added to the waitlist
- The signup process still returns true even when a team is waitlisted
Team Drop and Waitlist Promotion
describe '#drop_team' do before do project_topic.signup_team(team) project_topic.signup_team(Team.create!(assignment: assignment)) end context 'when dropping confirmed team' do it 'promotes waitlisted team' do waitlisted_team = Team.create!(assignment: assignment) waitlisted_team2 = Team.create!(assignment: assignment) project_topic.signup_team(waitlisted_team) project_topic.signup_team(waitlisted_team2) expect { project_topic.drop_team(team) }.to change { project_topic.confirmed_teams.count }.by(0) expect(waitlisted_team.reload.signed_up_teams.first.is_waitlisted).to be false expect(project_topic.waitlisted_teams.first).to eq(waitlisted_team2) end end end
This test verifies that:
- When a confirmed team drops a topic, the first waitlisted team is automatically promoted
- The promotion follows a FIFO (First-In-First-Out) order
- The total number of confirmed teams remains constant after the promotion
Slot Availability Calculations
describe '#available_slots' do it 'returns # of available slots correctly' do expect(project_topic.available_slots).to eq(2) project_topic.signup_team(team) expect(project_topic.available_slots).to eq(1) end end describe '#slot_available?' do it 'returns true when slots available' do expect(project_topic.slot_available?).to be true end it 'returns false when slots full' do 2.times { |n| project_topic.signup_team(Team.create!(assignment: assignment)) } expect(project_topic.slot_available?).to be false end end
This test verifies that:
- The system correctly calculates available slots
- The slot_available? method accurately reflects whether slots are available
Waitlisted Teams
describe '#waitlisted_teams' do it 'returns waitlisted teams in order' do teams = 5.times.map { Team.create!(assignment: assignment) } teams.each { |t| project_topic.signup_team(t) } # Ensures waitlisted teams are returned in the order they were added. 5.times { project_topic.signup_team(Team.create!(assignment: assignment)) } waitlisted = project_topic.waitlisted_teams expect(waitlisted.size).to eq(3) expect(waitlisted).to eq(waitlisted.sort_by(&:created_at)) end it 'returns empty array if no waitlisted teams' do # Returns an empty array when no teams are waitlisted. expect(project_topic.waitlisted_teams).to eq([]) end end
These tests verify that:
- That the method returns waitlisted teams sorted by the order in which they were added (FIFO).
- It returns an empty array if there are no waitlisted teams.
Validation Tests
describe 'validations' do it 'requires topic_name' do # Validates presence of topic_name field. topic = ProjectTopic.new(assignment: assignment, max_choosers: 1) expect(topic).not_to be_valid expect(topic.errors[:topic_name]).to include("can't be blank") end it 'requires non-negative integer for max_choosers' do # Validates that max_choosers is a non-negative number. topic = ProjectTopic.new(topic_name: "Invalid", assignment: assignment, max_choosers: -1) expect(topic).not_to be_valid expect(topic.errors[:max_choosers]).to include("must be greater than or equal to 0") end end
These tests verify that:
- A topic cannot be created without a topic_name, enforcing data integrity.
- The max_choosers attribute must be zero or positive, preventing invalid topic configurations.
Functional Tests
describe 'functional checks' do it 'increases confirmed team count on signup' do # Ensures that the count of confirmed teams increases after signup. expect { project_topic.signup_team(team) }.to change { project_topic.confirmed_teams.count }.by(1) end it 'does not allow more than max_choosers confirmed teams' do # Confirms that additional teams beyond limit go to waitlist. t1 = Team.create!(assignment: assignment) t2 = Team.create!(assignment: assignment) t3 = Team.create!(assignment: assignment) project_topic.signup_team(t1) project_topic.signup_team(t2) project_topic.signup_team(t3) expect(project_topic.confirmed_teams.count).to eq(2) expect(project_topic.waitlisted_teams.count).to eq(1) end it 'removes team’s other waitlisted entries on confirmed signup' do # Ensures a confirmed team is removed from other topic waitlists. t = Team.create!(assignment: assignment) t1 = ProjectTopic.create!(topic_name: "Alt Topic", assignment: assignment, max_choosers: 0) t1.signup_team(t) expect(t1.waitlisted_teams).to include(t) project_topic.signup_team(t) expect(t1.reload.waitlisted_teams).not_to include(t) end it 'get_signed_up_teams includes waitlisted and confirmed teams' do # Validates that all signed-up teams, regardless of status, are returned. t1 = Team.create!(assignment: assignment) t2 = Team.create!(assignment: assignment) project_topic.signup_team(t1) project_topic.signup_team(t2) expect(project_topic.get_signed_up_teams.map(&:team_id)).to include(t1.id, t2.id) end it 'slot_available? reflects accurate state after signup and drop' do # Checks dynamic behavior of slot availability after signup and drop. t1 = Team.create!(assignment: assignment) t2 = Team.create!(assignment: assignment) project_topic.signup_team(t1) project_topic.signup_team(t2) expect(project_topic.slot_available?).to be false project_topic.drop_team(t1) expect(project_topic.slot_available?).to be true end it 'signed_up_team records are removed when team is dropped' do # Confirms that dropping a team deletes the associated record. project_topic.signup_team(team) expect { project_topic.drop_team(team) }.to change { SignedUpTeam.count }.by(-1) end it 'multiple topics maintain independent signups' do # Ensures that signups in one topic do not affect another topic. topic2 = ProjectTopic.create!(topic_name: "Topic 2", assignment: assignment, max_choosers: 1) team2 = Team.create!(assignment: assignment) project_topic.signup_team(team) topic2.signup_team(team2) expect(project_topic.confirmed_teams).to include(team) expect(topic2.confirmed_teams).to include(team2) end it 'promotes the earliest waitlisted team after dropping a confirmed one' do # Ensures that when a confirmed team is dropped, the earliest waitlisted is promoted. t1 = Team.create!(assignment: assignment) t2 = Team.create!(assignment: assignment) t3 = Team.create!(assignment: assignment) project_topic.signup_team(t1) project_topic.signup_team(t2) project_topic.signup_team(t3) expect(project_topic.waitlisted_teams.first).to eq(t3) project_topic.drop_team(t1) expect(project_topic.confirmed_teams).to include(t2, t3) expect(project_topic.waitlisted_teams).to be_empty end it 'does not increase available slots after promoting a waitlisted team' do # Verifies that slot count remains constant when a waitlisted team is promoted. t1 = Team.create!(assignment: assignment) t2 = Team.create!(assignment: assignment) t3 = Team.create!(assignment: assignment) project_topic.signup_team(t1) project_topic.signup_team(t2) project_topic.signup_team(t3) expect(project_topic.available_slots).to eq(0) project_topic.drop_team(t1) expect(project_topic.available_slots).to eq(0) end end
These tests verify that:
- When a team is confirmed for one topic, it is removed from the waitlists of other topics.
- The method returns all signed-up teams, regardless of whether they are confirmed or waitlisted.
- Slot availability is updated correctly after teams sign up and after a team drops.
- Dropping a team from a topic deletes the corresponding signup record.
- Signing up for one topic does not affect signups for another topic.
- When a confirmed team is dropped, the team that has waited the longest on the waitlist is promoted to confirmed.
- Slot count remains constant when a waitlisted team is promoted.
SignedUpTeam Model Tests
The signed_up_team_spec.rb file tests the join model that connects teams and topics:
Validation Tests
describe 'validations' do it 'requires a project topic' do sut = SignedUpTeam.new(team: team) expect(sut).not_to be_valid expect(sut.errors[:project_topic]).to include("must exist") end it 'requires a team' do sut = SignedUpTeam.new(project_topic: project_topic) expect(sut).not_to be_valid expect(sut.errors[:team]).to include("must exist") end it 'enforces unique team per project topic' do SignedUpTeam.create!(project_topic: project_topic, team: team) duplicate = SignedUpTeam.new(project_topic: project_topic, team: team) expect(duplicate).not_to be_valid expect(duplicate.errors[:team]).to include("has already been taken") end end
These tests verify that:
- SignedUpTeam records require both a project_topic and a team
- A team cannot be signed up for the same topic multiple times
Scope Tests
describe 'scopes' do let!(:confirmed_signup) { SignedUpTeam.create!(project_topic: project_topic, team: team, is_waitlisted: false) } let!(:waitlisted_signup) { SignedUpTeam.create!(project_topic: project_topic, team: Team.create!(assignment: assignment), is_waitlisted: true) } it 'returns confirmed signups' do expect(SignedUpTeam.confirmed).to contain_exactly(confirmed_signup) end it 'returns waitlisted signups' do expect(SignedUpTeam.waitlisted).to contain_exactly(waitlisted_signup) end end
These tests verify that:
- The confirmed scope returns only non-waitlisted signups
- The waitlisted scope returns only waitlisted signups
Team Signup and Removal
describe 'signup_for_topic' do it 'delegates to project topic signup' do allow(project_topic).to receive(:signup_team).with(team).and_return(true) result = SignedUpTeam.signup_for_topic(team, project_topic) expect(result).to be true expect(project_topic).to have_received(:signup_team).with(team) end end describe 'remove_team_signups' do let!(:topic1) { ProjectTopic.create!(topic_name: "Topic 1", assignment: assignment) } let!(:topic2) { ProjectTopic.create!(topic_name: "Topic 2", assignment: assignment) } let!(:signup1) { SignedUpTeam.create!(project_topic: topic1, team: team) } let!(:signup2) { SignedUpTeam.create!(project_topic: topic2, team: team) } it 'removes all team signups across topics' do expect { SignedUpTeam.remove_team_signups(team) }.to change(SignedUpTeam, :count).by(-2) end end
These tests verify that:
- The signup_for_topic method correctly delegates to the project_topic's signup_team method
- The remove_team_signups method removes all signups for a team across all topics
Retrieving Participants for Teams
describe '.find_team_participants' do it 'returns all users in a given team' do participants = SignedUpTeam.find_team_participants(team.id) expect(participants).to contain_exactly(user1, user2) end it 'returns empty array if team does not exist' do expect(SignedUpTeam.find_team_participants(-1)).to eq([]) end it 'returns empty array when team exists but has no users' do new_team = Team.create!(assignment: assignment) expect(SignedUpTeam.find_team_participants(new_team.id)).to eq([]) end end
These tests verify that:
- The method correctly retrieves all users associated with a specified team and confirms that both the users are returned as participants for the team.
- It returns an empty array if team does not exist or if the team exists but has no users.
Identifying Users Associated with a Team
describe '.find_team_users' do let!(:sut) { SignedUpTeam.create!(project_topic: project_topic, team: team) } it 'returns users in the team that signed up' do users = SignedUpTeam.find_team_users(team.id) expect(users).to contain_exactly(user1, user2) end it 'returns empty array if no signed up team found' do new_team = Team.create!(assignment: assignment) expect(SignedUpTeam.find_team_users(new_team.id)).to eq([]) end it 'handles nil team_id gracefully' do expect(SignedUpTeam.find_team_users(nil)).to eq([]) end end
These tests verify that:
- The method fetches all users in a team that has a corresponding SignedUpTeam record and confirms that both users are returned for the signed-up team.
- It returns an empty array if no signed up team is found or if the team_id is a nil value.
Retrieve Topic details for Teams
describe '.find_user_signup_topics' do let!(:sut) { SignedUpTeam.create!(project_topic: project_topic, team: team) } it 'returns topics signed up by user’s team' do topics = SignedUpTeam.find_user_signup_topics(user1.id) expect(topics).to include(project_topic) end it 'returns empty array if user has no teams or no signups' do unknown = User.create!( name: "Ghost", full_name: "Ghost User", password: "password", email: "ghost@example.com", role: student_role ) expect(SignedUpTeam.find_user_signup_topics(unknown.id)).to eq([]) end it 'handles nil user_id gracefully' do expect(SignedUpTeam.find_user_signup_topics(nil)).to eq([]) end it 'handles user with multiple teams' do team2 = Team.create!(assignment: assignment) team2.users << user1 SignedUpTeam.create!(project_topic: project_topic, team: team2) topics = SignedUpTeam.find_user_signup_topics(user1.id) expect(topics).to include(project_topic) end end
These tests verify that
- The method returns all topics that the user’s team have signed up for and validates that the correct project_topic is included in the results for the user.
- It returns an empty array if the user has no teams or no signups or when a nil user_id is passed.
- The method aggregates topics from all teams a user belongs to, not just one and if a user is part of multiple teams, topics signed up by any of those teams are included in the result.
Resources
Pull Request : https://github.com/expertiza/reimplementation-back-end/pull/172
Demonstration : https://www.youtube.com/watch?v=1UiMUB7M4kA
Team
Mentor
- Dinesh Pasupuleti (dpasupu@ncsu.edu)
Members
- Adithya Srinivasan (asrini27@ncsu.edu)
- Smiti Kothari (skothar3@ncsu.edu)
- Dev Patel (dmpatel3@ncsu.edu)