Skip to content

Commit

Permalink
Merge pull request #161 from coursemology-collab/hanlin/groups-model
Browse files Browse the repository at this point in the history
Add Course::Group and Course::GroupUser
  • Loading branch information
lowjoel committed May 31, 2015
2 parents 84dc76d + 4ee7baa commit f4852a0
Show file tree
Hide file tree
Showing 14 changed files with 166 additions and 8 deletions.
1 change: 1 addition & 0 deletions app/models/course.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class Course < ActiveRecord::Base
has_many :announcements, inverse_of: :course, dependent: :destroy
has_many :achievements, inverse_of: :course, dependent: :destroy
has_many :levels, inverse_of: :course, dependent: :destroy
has_many :groups, inverse_of: :course, dependent: :destroy, class_name: Course::Group.name

delegate :staff, to: :course_users
delegate :has_user?, to: :course_users
Expand Down
19 changes: 19 additions & 0 deletions app/models/course/group.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
class Course::Group < ActiveRecord::Base
stampable

after_initialize :set_defaults, if: :new_record?
before_validation :set_defaults, if: :new_record?

belongs_to :course, inverse_of: :groups
has_many :group_users, inverse_of: :course_group, dependent: :destroy,
class_name: Course::GroupUser.name, foreign_key: :course_group_id
has_many :users, through: :group_users

private

# Set default values
def set_defaults
return unless creator && creator.courses.include?(course) && group_users.empty?
group_users.build(user: creator, role: :manager, creator: creator, updater: updater)
end
end
26 changes: 26 additions & 0 deletions app/models/course/group_user.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
class Course::GroupUser < ActiveRecord::Base
stampable

after_initialize :set_defaults, if: :new_record?

enum role: { normal: 0, manager: 1 }

validate :user_and_group_in_same_course

belongs_to :user, inverse_of: :course_group_users
belongs_to :course_group, class_name: Course::Group.name, inverse_of: :group_users

alias_method :group, :course_group

private

# Set default values
def set_defaults
self.role ||= :normal
end

def user_and_group_in_same_course #:nodoc:
return if user.courses.include?(group.course)
errors.add(:user, I18n.t('activerecord.errors.models.course_group_user.not_enrolled'))
end
end
3 changes: 3 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ class User < ActiveRecord::Base
has_many :instances, through: :instance_users
has_many :course_users, inverse_of: :user, dependent: :destroy
has_many :courses, through: :course_users
has_many :course_group_users, inverse_of: :user, dependent: :destroy,
class_name: Course::GroupUser.name
has_many :course_groups, through: :course_group_users, class_name: Course::Group.name

accepts_nested_attributes_for :emails

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
en:
activerecord:
errors:
models:
course_group_user:
not_enrolled: 'user must be enrolled in same course as group'
13 changes: 13 additions & 0 deletions db/migrate/20150513110737_create_course_groups.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class CreateCourseGroups < ActiveRecord::Migration
def change
create_table :course_groups do |t|
t.belongs_to :course, null: false
t.string :name, null: false, default: ''

t.userstamps null: false, foreign_key: { references: :users }
t.timestamps null: false

t.index [:course_id, :name], unique: true
end
end
end
14 changes: 14 additions & 0 deletions db/migrate/20150513111716_create_course_group_users.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class CreateCourseGroupUsers < ActiveRecord::Migration
def change
create_table :course_group_users do |t|
t.belongs_to :course_group, null: false
t.belongs_to :user, null: false
t.integer :role, null: false

t.userstamps null: false, foreign_key: { references: :users }
t.timestamps null: false

t.index [:user_id, :course_group_id], unique: true
end
end
end
37 changes: 29 additions & 8 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 20150512015621) do
ActiveRecord::Schema.define(version: 20150513111716) do

# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
Expand Down Expand Up @@ -105,13 +105,6 @@
t.datetime "updated_at", null: false
end

create_table "course_levels", force: :cascade do |t|
t.integer "course_id", null: false, index: {name: "fk__course_levels_course_id"}, foreign_key: {references: "courses", name: "fk_course_levels_course_id", on_update: :no_action, on_delete: :no_action}
t.integer "experience_points_threshold", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

create_table "course_users", force: :cascade do |t|
t.integer "course_id", null: false, index: {name: "fk__course_users_course_id"}, foreign_key: {references: "courses", name: "fk_course_users_course_id", on_update: :no_action, on_delete: :no_action}
t.integer "user_id", null: false, index: {name: "fk__course_users_user_id"}, foreign_key: {references: "users", name: "fk_course_users_user_id", on_update: :no_action, on_delete: :no_action}
Expand Down Expand Up @@ -139,6 +132,27 @@
t.datetime "updated_at", null: false
end

create_table "course_groups", force: :cascade do |t|
t.integer "course_id", null: false, index: {name: "fk__course_groups_course_id"}, foreign_key: {references: "courses", name: "fk_course_groups_course_id", on_update: :no_action, on_delete: :no_action}
t.string "name", default: "", null: false
t.integer "creator_id", null: false, index: {name: "fk__course_groups_creator_id"}, foreign_key: {references: "users", name: "fk_course_groups_creator_id", on_update: :no_action, on_delete: :no_action}
t.integer "updater_id", null: false, index: {name: "fk__course_groups_updater_id"}, foreign_key: {references: "users", name: "fk_course_groups_updater_id", on_update: :no_action, on_delete: :no_action}
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "course_groups", ["course_id", "name"], name: "index_course_groups_on_course_id_and_name", unique: true

create_table "course_group_users", force: :cascade do |t|
t.integer "course_group_id", null: false, index: {name: "fk__course_group_users_course_group_id"}, foreign_key: {references: "course_groups", name: "fk_course_group_users_course_group_id", on_update: :no_action, on_delete: :no_action}
t.integer "user_id", null: false, index: {name: "fk__course_group_users_user_id"}, foreign_key: {references: "users", name: "fk_course_group_users_user_id", on_update: :no_action, on_delete: :no_action}
t.integer "role", null: false
t.integer "creator_id", null: false, index: {name: "fk__course_group_users_creator_id"}, foreign_key: {references: "users", name: "fk_course_group_users_creator_id", on_update: :no_action, on_delete: :no_action}
t.integer "updater_id", null: false, index: {name: "fk__course_group_users_updater_id"}, foreign_key: {references: "users", name: "fk_course_group_users_updater_id", on_update: :no_action, on_delete: :no_action}
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "course_group_users", ["user_id", "course_group_id"], name: "index_course_group_users_on_user_id_and_course_group_id", unique: true

create_table "course_lesson_plan_items", force: :cascade do |t|
t.integer "actable_id"
t.string "actable_type", index: {name: "index_course_lesson_plan_items_on_actable_type_and_actable_id", with: ["actable_id"], unique: true}
Expand All @@ -154,6 +168,13 @@
t.datetime "updated_at", null: false
end

create_table "course_levels", force: :cascade do |t|
t.integer "course_id", null: false, index: {name: "fk__course_levels_course_id"}, foreign_key: {references: "courses", name: "fk_course_levels_course_id", on_update: :no_action, on_delete: :no_action}
t.integer "experience_points_threshold", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

create_table "instance_announcements", force: :cascade do |t|
t.integer "instance_id", null: false, index: {name: "fk__instance_announcements_instance_id"}, foreign_key: {references: "instances", name: "fk_instance_announcements_instance_id", on_update: :no_action, on_delete: :no_action}
t.string "title", limit: 255, null: false
Expand Down
20 changes: 20 additions & 0 deletions spec/factories/course_group_users.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FactoryGirl.define do
factory :course_group_user, class: Course::GroupUser.name do
course_group
user
role :normal
creator
updater

after(:build) do |group_user|
course = group_user.course_group.course
user = group_user.user
create(:course_user, course: course, user: user) unless user.courses.include?(course)
end

factory :course_group_student
factory :course_group_manager do
role :manager
end
end
end
8 changes: 8 additions & 0 deletions spec/factories/course_groups.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FactoryGirl.define do
factory :course_group, class: Course::Group.name do
course
sequence(:name) { |n| "Group #{n}" }
creator
updater
end
end
7 changes: 7 additions & 0 deletions spec/models/course/group_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
require 'rails_helper'

RSpec.describe Course::Group, type: :model do
it { is_expected.to belong_to(:course).inverse_of(:groups) }
it { is_expected.to have_many(:group_users).inverse_of(:course_group).dependent(:destroy) }
it { is_expected.to have_many(:users).through(:group_users) }
end
16 changes: 16 additions & 0 deletions spec/models/course/group_user_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
require 'rails_helper'

RSpec.describe Course::GroupUser, type: :model do
it { is_expected.to belong_to(:user).inverse_of(:course_group_users) }
it { is_expected.to belong_to(:course_group).inverse_of(:group_users) }

let!(:instance) { create(:instance) }
with_tenant(:instance) do
subject { build(:course_group_user) }

context 'when user is not enrolled in group\'s course' do
before { subject.user.course_users.delete_all }
it { is_expected.not_to be_valid }
end
end
end
1 change: 1 addition & 0 deletions spec/models/course_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
it { is_expected.to have_many(:users).through(:course_users) }
it { is_expected.to have_many(:announcements).inverse_of(:course).dependent(:destroy) }
it { is_expected.to have_many(:levels).inverse_of(:course).dependent(:destroy) }
it { is_expected.to have_many(:groups).inverse_of(:course).dependent(:destroy) }

it { is_expected.to validate_presence_of(:title) }

Expand Down
3 changes: 3 additions & 0 deletions spec/models/user_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
it { is_expected.to have_many(:instances).through(:instance_users) }
it { is_expected.to have_many(:course_users).inverse_of(:user).dependent(:destroy) }
it { is_expected.to have_many(:courses).through(:course_users) }
it { is_expected.to have_many(:course_group_users).inverse_of(:user).dependent(:destroy) }
it { is_expected.to have_many(:course_groups).through(:course_group_users) }


describe '#email' do
context 'when the user has no email addresses' do
Expand Down

0 comments on commit f4852a0

Please sign in to comment.