Class: Crm::CoursesController
- Inherits:
-
CrmController
- Object
- ActionController::Base
- ApplicationController
- CrmController
- Crm::CoursesController
- Defined in:
- app/controllers/crm/courses_controller.rb
Overview
Controller: courses.
Constant Summary
Constants included from Controllers::ReferenceFindable
Controllers::ReferenceFindable::ID_EMBEDDED_PATTERNS
Constants included from Controllers::AnalyticsEvents
Controllers::AnalyticsEvents::MAX_QUEUED_EVENTS, Controllers::AnalyticsEvents::SESSION_KEY
Constants included from Controllers::ErrorRendering
Controllers::ErrorRendering::NON_CONTENT_PATH_PREFIXES
Instance Method Summary collapse
-
#create ⇒ Object
Creates a course from
course_params. -
#destroy ⇒ Object
Destroys the course.
-
#edit ⇒ Object
Renders the form to edit an existing course.
-
#index ⇒ Object
Doubles as the training dashboard: program-wide stats plus per-course enrollment breakdowns.
-
#new ⇒ Object
Renders the form for a new course.
-
#show ⇒ Object
Shows a course's dashboard stats and recent enrollments.
-
#sync_enrollments ⇒ Object
Content sync: push active lesson topics added after learners enrolled into their active enrollments (per-learner CustomerTopic copies are snapshotted at enroll time, so later course edits don't reach them).
-
#update ⇒ Object
Updates a course from
course_params, or clears its image whenparams[:remove_image]is present.
Methods inherited from CrmController
#access_denied, #context_id, #context_object, #crm_home_path, #current_ability, #default_url_options, #download_temp, #get_tempfile_path_for_download, #init_status_job_collector, #initialize_crm_lazy_chunks, #persist_enqueued_status_jobs, #record_not_found, #redirect_to_job_or_fallback, #render_edit_action, #set_context, #set_download_path, #stash_file_for_temp_download, #sync_admin_presence_cookie, #touch_employee_last_seen
Methods inherited from ApplicationController
#account_impersonated?, #add_to_flash, #after_sign_in_path_for, #bypass_forgery_protection?, #chat_enabled?, #cloudflare_cleared?, #default_catalog, #default_url_options, #enable_turbo_frames, #find_publication, #fix_invalid_accept_header, #init_js_utils, #is_globals_call?, #layout_by_resource, #locale_store, #redirect_to, #require_employee_for_crm, #set_base_host, #set_real_ip, #set_report_errors_for, #should_render_layout?, #skip_layout_for_turbo_frame?, #stamp_impersonation_context, #tab_frame_breakout_request?, #warmlyyours_canada_ip?, #warmlyyours_ip?, #y
Methods included from Controllers::ReturnPathHandling
#check_for_return_path, #redirect_to_return_path_or_default
Methods included from Controllers::AnalyticsEvents
#consume_queued_analytics_events, #registration_lead_type, #track_event
Methods included from Controllers::DeviceDetection
Methods included from Controllers::SubdomainDetection
#is_crm_request?, #is_www_request?, #json_request?
Methods included from Controllers::TurboSafeRedirect
Methods included from Controllers::TrackingDetection
#bot_request?, #gdpr_country?, #gdpr_country_data, #prevent_bots, #set_tracking_cookie, #track_visitor?
Methods included from Controllers::AcceleratedFileSending
#send_file_accelerated, #send_upload_accelerated
Methods included from Controllers::ErrorRendering
#excp_string, #mail_to_for_error_reporting, #render_400, #render_404, #render_406, #render_410, #render_500, #render_invalid_authenticity_token, #render_ip_spoof_error, #render_unpermitted_parameters, #safe_referer_or_fallback
Methods included from Controllers::TurnstileVerification
#load_turnstile_script_tag, #turnstile_lazy_widget, #turnstile_script_tag, #turnstile_widget, #validate_turnstile!
Methods included from Controllers::CloudflareCaching
edge_cached, #edge_cached_action?, #reset_cloudflare_cache, #set_cloudflare_cache, #skip_edge_cache!, #skip_session
Methods included from Controllers::Webpackable
#preload_webpack_fonts, #webpack_css_include, #webpack_css_url, #webpack_js_include, #wpd_is_running?
Methods included from Controllers::Localizable
#cloudflare_country_locale, #determine_request_locale, #geocoder_locale, #guest_user_locale_check, #locale_optional_www_auth_path?, #param_locale, #set_locale, #set_request_locale, #skip_localization?, #warmlyyours_ip_locale
Methods included from Controllers::Authenticable
#access_denied, #authenticate_account, #authenticate_account!, #authenticate_account_from_login_token!, #check_is_a_manager, #check_is_a_sales_manager, #check_is_an_admin, #check_is_an_employee, #check_party, #clear_mismatched_guest_user, #create_guest_user, #credentials?, #current_or_guest_user, #current_or_guest_user_id_read_only, #current_user, #devise_mapping, #fully_logged_in?, #generate_bot_id, #guest_user, #identifiable?, #init_current_user, #initialize_guest, #load_context_user, #logging_in, #resource, #resource_name, #restrict_access_for_non_employees, #scrubbed_request_path, #user_object, #warn_on_session_guest_id_leak
Methods included from UrlsHelper
#catalog_breadcrumb_links, #catalog_link, #catalog_link_for_product_line, #catalog_link_for_sku, #cms_link, #delocalized_path, #path_to_sales_product_sku, #path_to_sales_product_sku_for_product_line, #path_to_sales_product_sku_for_product_line_slug, #product_line_from_catalog_link, #protocol_neutral_url, #sanitize_external_url, #valid_external_url?
Instance Method Details
#create ⇒ Object
Creates a course from course_params.
55 56 57 58 59 60 61 62 63 |
# File 'app/controllers/crm/courses_controller.rb', line 55 def create @course = Course.new(course_params) :create, @course if @course.save redirect_to @course, notice: 'Course created' else render :new, status: :unprocessable_content end end |
#destroy ⇒ Object
Destroys the course.
83 84 85 86 87 88 89 90 91 92 |
# File 'app/controllers/crm/courses_controller.rb', line 83 def destroy :destroy, @course @course.destroy if @course.errors.present? flash[:error] = @course.errors_to_s else flash[:info] = "#{@course.id} deleted" end redirect_to url_for(action: :index) end |
#edit ⇒ Object
Renders the form to edit an existing course.
50 51 52 |
# File 'app/controllers/crm/courses_controller.rb', line 50 def edit :update, @course end |
#index ⇒ Object
Doubles as the training dashboard: program-wide stats plus per-course
enrollment breakdowns.
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'app/controllers/crm/courses_controller.rb', line 11 def index @courses = Course.all.ransack(params[:q]).result.order(:name) graded_exams = CourseExam.where(state: %w[passed failed]) @stats = { enrollments: CourseEnrollment.count, active_learners: CourseEnrollment.where(state: 'active').count, completed: CourseEnrollment.where(state: 'completed').count, graded_exams: graded_exams.count, passed_exams: graded_exams.where(state: 'passed').count, active_certifications: Certification.active.count, requested_certifications: Certification.requested.count, expiring_soon: Certification.active.where(expires_at: ..30.days.from_now).count } # { [course_id, state] => count } — one query for the whole table. @enrollment_counts = CourseEnrollment.group(:course_id, :state).count # Precompute per-course totals to avoid scanning and summing the hash per course in the view. @enrollment_totals = CourseEnrollment.group(:course_id).count # Precompute per-course exam counts to avoid N+1 queries in the view. @graded_counts = CourseExam.joins(:course_enrollment).where(state: %w[passed failed]).group(:course_id).count @passed_counts = CourseExam.joins(:course_enrollment).where(state: 'passed').group(:course_id).count end |
#new ⇒ Object
Renders the form for a new course.
44 45 46 47 |
# File 'app/controllers/crm/courses_controller.rb', line 44 def new @course = Course.new :create, @course end |
#show ⇒ Object
Shows a course's dashboard stats and recent enrollments.
35 36 37 38 39 40 41 |
# File 'app/controllers/crm/courses_controller.rb', line 35 def show dashboard = Course::DashboardStats.call(@course) @topic_categories = dashboard.topic_categories @topic_exams = dashboard.topic_exams @recent_enrollments = dashboard.recent_enrollments @stats = dashboard.stats end |
#sync_enrollments ⇒ Object
Content sync: push active lesson topics added after learners enrolled
into their active enrollments (per-learner CustomerTopic copies are
snapshotted at enroll time, so later course edits don't reach them).
GET renders a preview with the exact counts; POST applies it.
For bulk operations >BULK_SYNC_THRESHOLD, requires two explicit
confirmations separated by user interaction to prevent accidental
mass assignments.
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'app/controllers/crm/courses_controller.rb', line 102 def sync_enrollments :update, @course @additions = missing_topic_assignments @total = @additions.values.sum(&:size) return unless request.post? # Validate batch ID and confirmation state for two-stage confirmation. @batch = CourseSyncBatch.find(params.expect(:batch_id)) unless @batch.course_id == @course.id && @batch.pending? flash[:error] = 'Invalid or expired sync batch. Please try again.' redirect_to sync_enrollments_course_path(@course) return end # For large batches, require a second confirmation. confirmation_state = params.dig(:confirmation_state) if @batch.large_batch? && confirmation_state != 'confirmed' # Pass confirmation_state through URL so the view knows we're awaiting final confirmation. redirect_to sync_enrollments_course_path(@course, confirmation_state: confirmation_state || 'awaiting_final'), status: :see_other return end # Store affected records before applying changes (for potential rollback). @batch.store_affected_records!(@additions) @batch.mark_processing! created = 0 @additions.each do |enrollment, topics| topics.each do |topic| created += 1 if assign_missing_topic(enrollment, topic) end end @batch.mark_completed!(assigned: created, failed: @batch.total_topics_to_assign - created) flash[:info] = "Content sync complete — #{created} #{'topic'.pluralize(created)} assigned across #{@additions.size} #{'enrollment'.pluralize(@additions.size)}." redirect_to course_path(@course) rescue ActiveRecord::RecordNotFound flash[:error] = 'Sync batch not found. Please try again.' redirect_to sync_enrollments_course_path(@course) end |
#update ⇒ Object
Updates a course from course_params, or clears its image when
params[:remove_image] is present.
67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'app/controllers/crm/courses_controller.rb', line 67 def update :update, @course if params[:remove_image].present? if @course.update(image_uid: nil, image_name: nil) redirect_to edit_course_path(@course), notice: 'Image removed' else render :edit, status: :unprocessable_content end elsif @course.update(course_params) redirect_to @course, notice: 'Course updated' else render :edit, status: :unprocessable_content end end |