Need help with Devise and enrollment system in Rails: How to implement 'Enroll Now' button?

I’m working on a Rails app with Devise for user authentication. I want to add an ‘Enroll Now’ button that creates a record when a user views a lesson. Here’s my current setup:

class Student
  has_many :completed_modules
  has_many :enrolled_programs
end

class Module
  belongs_to :program
end

class Program
  has_many :modules
end

class CompletedModule
  belongs_to :student
  belongs_to :module
  attribute :finished, :boolean
end

class EnrolledProgram
  belongs_to :student
  belongs_to :program
  attribute :finished, :boolean
end

class ProgramsController < ApplicationController
  def display
    @program = Program.find(params[:id])
    current_student.enrolled_programs.find_or_create_by(program: @program)
  end
end

How can I modify this to add the ‘Enroll Now’ feature? Also, how do I prevent creating duplicate records when a student views the same program multiple times? Any help would be great. Thanks!

Hey there, GracefulDancer8! :wave: Your project sounds super interesting! I’m curious about a few things though.

Have you considered using a service object for your enrollment logic? It might help keep your controller nice and lean. Something like:

class EnrollmentService
  def self.enroll(student, program)
    return false if student.enrolled_programs.exists?(program: program)
    student.enrolled_programs.create(program: program)
    true
  end
end

Then in your controller, you could do:

def enroll
  @program = Program.find(params[:id])
  if EnrollmentService.enroll(current_student, @program)
    flash[:notice] = 'Yay! You\'re enrolled! 🎉'
  else
    flash[:alert] = 'Oops! Already enrolled in this one.'
  end
  redirect_to @program
end

What do you think? Would that work for your use case?

Also, I’m wondering how you’re handling the UI for this. Are you using any JavaScript to make it more dynamic? It’d be cool to see the button change instantly when a user enrolls!

Let me know if you want to bounce around any other ideas. Always fun to chat about Rails projects! :blush:

yo gracefuldancer8, here’s a quick fix for ur enroll button:

  1. add a route: post ‘/programs/:id/enroll’, to: ‘programs#enroll’
  2. in ProgramsController:
def enroll
  @program = Program.find(params[:id])
  current_student.enrolled_programs.find_or_create_by(program: @program)
  redirect_to @program, notice: 'enrolled!'
end

this’ll handle duplicate enrollments too. lmk if u need anything else!

I’ve faced a similar challenge with enrollment systems. Here’s what worked for me:

Modify your ProgramsController to include an ‘enroll’ action:

def enroll
  @program = Program.find(params[:id])
  enrollment = current_student.enrolled_programs.find_or_create_by(program: @program)
  
  if enrollment.persisted?
    flash[:notice] = 'Successfully enrolled in the program.'
  else
    flash[:alert] = 'You are already enrolled in this program.'
  end
  
  redirect_to program_path(@program)
end

This approach uses find_or_create_by to prevent duplicate enrollments. It’s efficient and handles the logic in one go.

For the ‘Enroll Now’ button, add this to your view:

<%= button_to 'Enroll Now', enroll_program_path(@program), method: :post %>

Don’t forget to add the corresponding route in your routes.rb:

post '/programs/:id/enroll', to: 'programs#enroll', as: 'enroll_program'

This setup should give you a clean, functional enrollment system without duplicates.