The project is in a healthy, maintained state
Interns record their work experience hours and projects, and mentors review them
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Project Readme

Effective Work Experience

Interns record their work experience hours and projects, and mentors review them.

Interns record their hours each month against a set of work experience subcategories, and record the projects they worked on. Every few months they submit a summary of that period, which is reviewed by their mentor. A work experience report totals everything to date against the minimum hours of each category.

Getting Started

This requires Rails 6+ and Twitter Bootstrap 4 and just works with Devise.

Please first install the effective_datatables gem.

Please download and install the Twitter Bootstrap4

Add to your Gemfile:

gem 'effective_work_experience'

Run the bundle command to install it:

bundle install

Then run the generator:

rails generate effective_work_experience:install

The generator will install an initializer which describes all configuration options and creates a database migration.

Then migrate the database:

rake db:migrate

Models

  • Effective::WorkExperienceCategory — the top level grouping, with a minimum hours target
  • Effective::WorkExperienceSubcategory — belongs to a category. Hours are recorded against these.
  • Effective::WorkExperienceRecord — one intern's hours for one month
  • Effective::WorkExperienceEntry — one row of a record. Five weeks of hours for one subcategory.
  • Effective::WorkExperienceProject — one project an intern worked on
  • Effective::WorkExperienceSummary — one period, submitted by the intern and reviewed by their mentor
  • Effective::WorkExperienceOutsideMentor — a mentor without an account, stored as freeform fields
  • Effective::WorkExperienceReport — an ActiveModel report of everything to date

The work experience summary is the only swappable class. Mark your own with effective_work_experience_summary:

module Bcsla
  class WorkExperienceSummary < ApplicationRecord
    effective_work_experience_summary
  end
end

and configure it:

config.work_experience_summary_class_name = 'Bcsla::WorkExperienceSummary'

User

Add the following to your User model:

effective_work_experience_user

This requires a work_experience_mentor_id column on your users table, and adds:

  • work_experience_mentor — the user who reviews my work experience summaries
  • work_experience_mentees — the interns I am a mentor for
  • work_experience_outside_mentor — my mentor when they don't have an account. A has_one.
  • work_experience_records, work_experience_entries, work_experience_projects, work_experience_summaries, mentee_work_experience_summaries
  • the work_experience_hours, work_experience_hours_by_year and work_experience_total_hours_to_date calculations

An intern with an outside mentor has no work_experience_mentor, so their summaries are reviewed automatically on submit.

The summary's user, mentor and supervisor are polymorphic. A summary assigns its mentor from the user's work_experience_mentor, and its supervisor from the user's supervisor when your User model defines one.

Render the mentor fields from your own admin user form:

= render('effective/work_experience/user_fields', f: f)

This is the work_experience_mentor select plus an f.has_many builder for the one outside mentor.

Dashboard

Render the dashboard partials from your own dashboard:

- if current_user.work_experience_intern?
  = render 'effective/work_experience/dashboard_intern'

- if current_user.work_experience_mentor?
  = render 'effective/work_experience/dashboard_mentor'

Configuration

All configuration options are documented in the config/initializers/effective_work_experience.rb initializer.

Authorization

All authorization checks are handled via the effective_resources gem found in the config/initializers/effective_resources.rb file.

Permissions

The permissions you actually want to define are as follows (using CanCan):

if user.persisted?
  can([:index, :show, :new, :create], Effective::WorkExperienceRecord) { |record| record.user == user }
  can([:edit, :update], Effective::WorkExperienceRecord) { |record| !record.backdated? && !record.was_reviewed? }
  can(:destroy, Effective::WorkExperienceRecord) { |record| !record.backdated? && !record.was_submitted? }

  can(crud, Effective::WorkExperienceProject) { |project| project.user == user }

  can([:new, :create], EffectiveWorkExperience.WorkExperienceSummary) { |summary| summary.user == user }
  can(:destroy, EffectiveWorkExperience.WorkExperienceSummary) { |summary| summary.user == user && summary.draft? }

  can([:show, :index], EffectiveWorkExperience.WorkExperienceSummary) do |summary|
    summary.user == user || (summary.mentor == user && summary.was_submitted?)
  end

  can(:update, EffectiveWorkExperience.WorkExperienceSummary) do |summary|
    (summary.user == user && !summary.was_submitted?) || (summary.mentor == user && summary.was_submitted?)
  end

  can(:show, Effective::WorkExperienceReport) { |report| report.user == user || report.mentor == user }

  if user.work_experience_mentor?
    can(:index, EffectiveWorkExperienceReportsReviewDatatable)
  end
end

if user.admin?
  can :admin, :effective_work_experience

  can([:index, :edit, :update], Effective::WorkExperienceCategory)
  can([:index, :edit, :update], Effective::WorkExperienceSubcategory)
  can(crud - [:show], Effective::WorkExperienceProject)
  can(crud - [:show], Effective::WorkExperienceRecord)
  can(crud, Effective::WorkExperienceReport)
  can(crud, EffectiveWorkExperience.WorkExperienceSummary)
  can(:index, Admin::EffectiveWorkExperienceReportsDatatable)
end

Add a link to the admin menu:

- if can? :admin, :effective_work_experience
  = nav_link_to Effective::WorkExperienceRecord, effective_work_experience.admin_work_experience_records_path
  = nav_link_to Effective::WorkExperienceProject, effective_work_experience.admin_work_experience_projects_path
  = nav_link_to EffectiveWorkExperience.WorkExperienceSummary, effective_work_experience.admin_work_experience_summaries_path
  = nav_link_to Effective::WorkExperienceReport, effective_work_experience.admin_work_experience_reports_path

License

MIT License. Copyright Code and Effect Inc.

Testing

Run tests by:

rails test

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Bonus points for test coverage
  6. Create new Pull Request