Edit #2
Here is the courses controller
class CoursesController < ApplicationController
layout proc { user_signed_in? ? "dashboard" : "application" }
before_action :set_course, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
before_action :authorize_admin, except: [:index, :show, :complete]
def index
@courses = Course.all.order(created_at: :asc)
end
def show
course = Course.friendly.find(params[:id])
@course_modules = course.course_modules.order(created_at: :asc)
end
def new
@course = Course.new
end
def edit
end
def create
@course = Course.new(course_params)
respond_to do |format|
if @course.save
format.html { redirect_to courses_path, notice: 'Course was successfully created.' }
format.json { render :show, status: :created, location: courses_path }
else
format.html { render :new }
format.json { render json: @course.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if @course.update(course_params)
format.html { redirect_to @course, notice: 'Course was successfully updated.' }
format.json { render :show, status: :ok, location: @course }
else
format.html { render :edit }
format.json { render json: @course.errors, status: :unprocessable_entity }
end
end
end
def destroy
@course.destroy
respond_to do |format|
format.html { redirect_to courses_url, notice: 'Course was successfully destroyed.' }
format.json { head :no_content }
end
end
private
def set_course
@course = Course.friendly.find(params[:id])
end
def course_params
params.require(:course).permit(:title, :summary, :description, :trailer, :price)
end
end
Edit #1
So going off Jagdeep's answer below I have now done the following:
course.rb
class Course < ApplicationRecord
extend FriendlyId
friendly_id :title, use: :slugged
has_many :course_modules
validates :title, :summary, :description, :trailer, :price, presence: true
def complete?
self.update_attribute(:complete, true)
end
end
course_modules_user.rb
class CourseModulesUser < ApplicationRecord
belongs_to :course_module
belongs_to :user
def complete!
self.update_attribute(:complete, true)
end
end
courses_user.rb
class CoursesUser < ApplicationRecord
belongs_to :course
belongs_to :user
end
user.rb
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
has_one_attached :avatar
has_many :courses_users
has_many :courses, through: :courses_users
has_many :course_modules_users
has_many :course_modules, through: :course_modules_users
def mark_course_module_complete!(course_module)
self.course_modules_users
.where(course_module_id: course_module.id)
.first
.complete!
end
def after_confirmation
welcome_email
super
end
protected
def welcome_email
UserMailer.welcome_email(self).deliver
end
end
Migrations
class CreateCoursesUsers < ActiveRecord::Migration[5.2]
def change
create_table :courses_users do |t|
t.integer :course_id
t.integer :user_id
t.boolean :complete
t.timestamps
end
end
end
class CreateCourseModulesUsers < ActiveRecord::Migration[5.2]
def change
create_table :course_modules_users do |t|
t.integer :course_module_id
t.integer :user_id
t.boolean :complete
t.timestamps
end
end
end
However, I'm getting errors like this
Original Question
So this is a continuation of a previous question, however, this will stray off from the topic of that so here is a new one.
After this, I got roughly what I wanted to get working which is allowing people to mark off modules and make the course complete if all modules are complete. However, upon testing a new user the modules and courses are being marked as complete (obviously a new user isn't going to complete the course on sign-in, nor are any modules going to be complete) so I need for all users to be separate in terms of what is marked as complete and what isn't.
Previously a user by the name of @engineersmnky mentioned HABTM relationship, however, I've not dealt with this previously.
Here is how I have things setup thus far:
user.rb
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
has_one_attached :avatar
has_many :courses
def after_confirmation
welcome_email
super
end
protected
def welcome_email
UserMailer.welcome_email(self).deliver
end
end
course.rb
class Course < ApplicationRecord
extend FriendlyId
friendly_id :title, use: :slugged
has_many :users
has_many :course_modules
validates :title, :summary, :description, :trailer, :price, presence: true
def complete!
update_attribute(:complete, true)
end
end
course_module.rb
class CourseModule < ApplicationRecord
extend FriendlyId
friendly_id :title, use: :slugged
belongs_to :course
has_many :course_exercises
validates :title, :course_id, presence: true
scope :completed, -> { where(complete: true) }
after_save :update_course, if: :complete?
private
def update_course
course.complete! if course.course_modules.all?(&:complete?)
end
end
if the course is complete conditional courses/index.html.erb
<% if course.complete? %>
<%= link_to "Completed", course, class: "block text-lg w-full text-center text-white px-4 py-2 bg-green hover:bg-green-dark border-2 border-green-dark leading-none no-underline" %>
<% else %>
<%= link_to "View Modules", course, class: "block text-lg w-full text-center text-grey-dark hover:text-darker px-4 py-2 border-2 border-grey leading-none no-underline hover:border-2 hover:border-grey-dark" %>
<% end %>
if course module is complete conditional courses/show.html.erb
<% if course_module.complete? %>
<i class="fas fa-check text-green float-left mr-1"></i>
<span class="text-xs mr-2">Completed</span>
<% else %>
<%= link_to complete_course_module_path(course_module), method: :put do %>
<i class="fas fa-check text-grey-darkest float-left mr-2"></i>
<% end %>
Databases
Course Modules
Courses