From 0cbfdda969e2a18c98a52e477474b321d57274be Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 8 Apr 2026 14:19:39 +0800 Subject: [PATCH 1/3] feat: revamped projects/new, updated breadcrumb --- app/controllers/projects_controller.rb | 19 +-- app/policies/project_policy.rb | 6 +- app/views/courses/_topic_card.html.erb | 2 +- app/views/projects/new.html.erb | 167 +++++++++++++---------- app/views/topics/_topic_actions.html.erb | 19 ++- app/views/topics/_topic_fields.html.erb | 9 +- app/views/topics/show.html.erb | 3 +- config/breadcrumbs.rb | 16 ++- 8 files changed, 149 insertions(+), 92 deletions(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 15aad414..429ab979 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -82,17 +82,18 @@ def new @lecturer_options = Enrolment.where(course: @course, role: :lecturer).includes(:user) - @field_values = {} - - # Optionally preselect topic or own proposal - topic_id = params[:topic_id].presence || params[:based_on_topic] + # Choose Supervisor + @lecturers = @course.lecturers + @lecturer_capacity_info = {} + @lecturers.each do |lecturer| + @lecturer_capacity_info[lecturer.id] = @course.lecturer_capacity(lecturer) + end - return unless topic_id.present? + @field_values = {} - if topic_id.to_s.start_with?('own_proposal_') - @selected_topic_id = topic_id - elsif @course.topics.exists?(id: topic_id) - @selected_topic_id = topic_id + # Based on Topic + if params[:topic_id].present? + @selected_topic = @course.topics.find_by(id: params[:topic_id]) end end diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index a80ade00..fa20e17f 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -49,7 +49,7 @@ def show? end def create? - student || coordinator + student && !has_existing_project? end def update? @@ -98,4 +98,8 @@ def student def approved record.status.to_s == 'approved' end + + def has_existing_project? + course.projects.owned_by_user(user).exists? + end end diff --git a/app/views/courses/_topic_card.html.erb b/app/views/courses/_topic_card.html.erb index 97b79a69..94fb809d 100644 --- a/app/views/courses/_topic_card.html.erb +++ b/app/views/courses/_topic_card.html.erb @@ -21,7 +21,7 @@ if local_assigns[:lecturer].present? course_lecturer_topic_path(course, lecturer, topic) else - course_topic_path(@course, topic) + course_topic_path(@course, topic, from_new_project: params[:from_new_project]) end card_classes = diff --git a/app/views/projects/new.html.erb b/app/views/projects/new.html.erb index 9acf427e..c87e56e1 100644 --- a/app/views/projects/new.html.erb +++ b/app/views/projects/new.html.erb @@ -71,82 +71,111 @@ <% input_classes = "w-full px-4 py-3 border border-gray-200 rounded-lg sm:rounded-xl text-gray-700 bg-gray-50 focus:outline-none focus:ring-4 focus:ring-blue-500/10 focus:border-blue-500 transition-all font-medium placeholder-gray-400 text-sm sm:text-base" %> -
-
+ <%# --- PROPOSE BASED ON TOPIC ACTION --- %> + <% if policy(Project.new(course: @course)).create? %> + <%= link_to new_course_project_path(@course, topic_id: @topic.id, from_topics: true), + class: "flex items-center justify-center w-full gap-2 bg-white border-2 border-blue-100 text-blue-600 hover:bg-blue-50 hover:border-blue-200 font-bold py-2.5 px-4 rounded-xl transition-colors group" do %> +
+ + + +
+ Propose Based on This Topic + <% end %> + <% end %> + diff --git a/app/views/topics/_topic_fields.html.erb b/app/views/topics/_topic_fields.html.erb index 6950aaa4..7b5605e1 100644 --- a/app/views/topics/_topic_fields.html.erb +++ b/app/views/topics/_topic_fields.html.erb @@ -84,16 +84,11 @@ <% end %> - <% if is_student %> - <%= link_to "Propose Based on this Topic", - new_course_project_path(course, topic_id: topic.id), - class: - "inline-flex items-center justify-center px-6 py-3 text-base font-semibold text-white transition-all duration-200 bg-blue-600 rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 hover:shadow-md" %> - <% end %> + - <%# ---DIFF TOOL--- %> + <%# DIFF TOOL %> <% if index < instances.size %>
<% has_actions = - @members.include?(current_user) || @current_version != @latest_version %> + @members.include?(current_user) || @current_version != @latest_version || + policy(Project.new(course: @course)).create? %> <% if has_actions %>
Date: Sat, 11 Apr 2026 11:01:51 +0800 Subject: [PATCH 2/3] feat: finishing up js for mutually exclusive based on topic/own proposal and fixed seeds --- app/controllers/projects_controller.rb | 71 +++--- app/javascript/application.js | 4 + app/javascript/controllers/index.js | 2 +- .../proposal_selection_controller.js | 80 +++++++ app/views/projects/new.html.erb | 225 ++++++++++++------ db/seeds.rb | 73 +++--- 6 files changed, 300 insertions(+), 155 deletions(-) create mode 100644 app/javascript/controllers/proposal_selection_controller.js diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 429ab979..9647ef71 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -91,9 +91,16 @@ def new @field_values = {} - # Based on Topic if params[:topic_id].present? @selected_topic = @course.topics.find_by(id: params[:topic_id]) + if @selected_topic + latest_instance = @selected_topic.current_instance + @field_values = latest_instance.project_instance_fields.each_with_object({}) do |f, h| + h[f.project_template_field_id.to_i] = f.value + end + end + elsif params[:lecturer_id].present? + @selected_lecturer = @course.lecturers.find_by(id: params[:lecturer_id]) end end @@ -136,29 +143,20 @@ def create raise StandardError, 'You already have a project' if has_project end - raise StandardError, 'Please choose a lecturer and topic' if params[:based_on_topic].blank? - - if params[:based_on_topic].start_with?('own_proposal_') - # Extract lecturer ID from value - lecturer_id = params[:based_on_topic].split('_').last.to_i + topic = Topic.find_by(id: params[:based_on_topic], course: @course) if params[:based_on_topic].present? + lecturer_id = params[:lecturer_id].presence - # Find lecturer enrolment for course - supervisor_enrolment = Enrolment.find_by(user_id: lecturer_id, course_id: @course.id, role: :lecturer) - - raise StandardError unless supervisor_enrolment - else - # Treat as topic_id - topic = Topic.find_by(id: params[:based_on_topic], course: @course) + raise StandardError, 'Please choose a lecturer or topic' if topic.nil? && lecturer_id.nil? - raise StandardError unless topic - - # Set supervisor enrolment to the owner of the topic (assuming you want this) - topic_owner = topic&.owner - raise StandardError unless topic_owner.is_a?(User) + if topic + topic_owner = topic.owner + raise StandardError, 'Topic has no valid owner' unless topic_owner.is_a?(User) supervisor_enrolment = Enrolment.find_by(user_id: topic_owner.id, course_id: @course.id, role: :lecturer) - - raise StandardError unless supervisor_enrolment + raise StandardError, 'Could not find supervisor enrolment' unless supervisor_enrolment + else + supervisor_enrolment = Enrolment.find_by(user_id: lecturer_id, course_id: @course.id, role: :lecturer) + raise StandardError, 'Could not find supervisor enrolment' unless supervisor_enrolment end @project = Project.create!( @@ -259,32 +257,21 @@ def update end end - raise StandardError, 'Please choose a lecturer and topic' if params[:based_on_topic].blank? - - # 2 formats, PROJECT_ID or own_proposal_LECTURER_ID - if params[:based_on_topic].start_with?('own_proposal_') - # Extract lecturer ID from value - lecturer_id = params[:based_on_topic].split('_').last.to_i + topic = Topic.find_by(id: params[:based_on_topic], course: @course) if params[:based_on_topic].present? + lecturer_id = params[:lecturer_id].presence - # Find lecturer enrolment for course - supervisor_enrolment = Enrolment.find_by(id: lecturer_id, course_id: @course.id, role: :lecturer) - - raise StandardError unless supervisor_enrolment - - @instance.update!(source_topic_id: nil) - else - # Treat as topic_id - topic = Topic.find_by(id: params[:based_on_topic], course: @course) - - raise StandardError unless topic - - raise StandardError unless topic.owner.is_a?(User) + raise StandardError, 'Please choose a lecturer or topic' if topic.nil? && lecturer_id.nil? + if topic + raise StandardError, 'Topic has no valid owner' unless topic.owner.is_a?(User) supervisor_enrolment = Enrolment.find_by(user_id: topic.owner.id, course_id: @course.id, role: :lecturer) - - raise StandardError unless supervisor_enrolment - + + raise StandardError, 'Could not find supervisor enrolment' unless supervisor_enrolment @instance.update!(source_topic: topic) + else + supervisor_enrolment = Enrolment.find_by(user_id: lecturer_id, course_id: @course.id, role: :lecturer) + raise StandardError, 'Could not find supervisor enrolment' unless supervisor_enrolment + @instance.update!(source_topic_id: nil) end @project.project_instances.last.update!( diff --git a/app/javascript/application.js b/app/javascript/application.js index 7d1db6d6..0d80407b 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -7,3 +7,7 @@ import "htmx.org"; document.addEventListener("turbo:load", function () { window.htmx.process(document.body); }); + +Turbo.config.drive.confirmationMethod = (message, element, submitter) => { + return Promise.resolve(window.confirm(message)); +}; \ No newline at end of file diff --git a/app/javascript/controllers/index.js b/app/javascript/controllers/index.js index fccc1dcb..ddb5d1a8 100644 --- a/app/javascript/controllers/index.js +++ b/app/javascript/controllers/index.js @@ -1,4 +1,4 @@ // Import and register all your controllers from the importmap via controllers/**/*_controller import { application } from "controllers/application"; import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"; -eagerLoadControllersFrom("controllers", application); +eagerLoadControllersFrom("controllers", application); \ No newline at end of file diff --git a/app/javascript/controllers/proposal_selection_controller.js b/app/javascript/controllers/proposal_selection_controller.js new file mode 100644 index 00000000..93dab54a --- /dev/null +++ b/app/javascript/controllers/proposal_selection_controller.js @@ -0,0 +1,80 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = ["lecturerPanel", "topicPanel", "hiddenLecturerId", "hiddenTopicId"] + + connect() { + // Restore initial state from server-rendered hidden fields on page load + const lecturerId = this.hiddenLecturerIdTarget.value + const topicId = this.hiddenTopicIdTarget.value + + if (lecturerId) { + this.#disablePanel(this.topicPanelTarget) + } else if (topicId) { + this.#disablePanel(this.lecturerPanelTarget) + } + } + + selectLecturer(event) { + const button = event.currentTarget + const lecturerId = button.dataset.lecturerId + const isAlreadySelected = this.hiddenLecturerIdTarget.value === lecturerId + + if (isAlreadySelected) { + // Deselect + this.hiddenLecturerIdTarget.value = "" + this.#markSelected(button, false) + this.#enablePanel(this.topicPanelTarget) + } else { + // Warn if topic is already selected + if (this.hiddenTopicIdTarget.value) { + if (!confirm("You'll lose your selected topic. Continue?")) return + this.hiddenTopicIdTarget.value = "" + } + + this.hiddenLecturerIdTarget.value = lecturerId + this.#clearAllLecturerSelections() + this.#markSelected(button, true) + this.#disablePanel(this.topicPanelTarget) + this.#enablePanel(this.lecturerPanelTarget) + } + } + + // Called by the "Clear" link next to the lecturer heading + clearLecturer(event) { + event.preventDefault() + this.hiddenLecturerIdTarget.value = "" + this.#clearAllLecturerSelections() + this.#enablePanel(this.topicPanelTarget) + } + + // Private + + #clearAllLecturerSelections() { + this.lecturerPanelTarget + .querySelectorAll("button[data-lecturer-id]") + .forEach(btn => this.#markSelected(btn, false)) + } + + #markSelected(button, selected) { + const check = button.querySelector("[data-selected-check]") + + if (selected) { + button.classList.add("border-blue-400", "ring-2", "ring-blue-100") + button.classList.remove("border-gray-200", "hover:border-gray-400") + if (check) check.classList.remove("hidden") + } else { + button.classList.remove("border-blue-400", "ring-2", "ring-blue-100") + button.classList.add("border-gray-200", "hover:border-gray-400") + if (check) check.classList.add("hidden") + } + } + + #disablePanel(panel) { + panel.classList.add("opacity-50", "pointer-events-none") + } + + #enablePanel(panel) { + panel.classList.remove("opacity-50", "pointer-events-none") + } +} \ No newline at end of file diff --git a/app/views/projects/new.html.erb b/app/views/projects/new.html.erb index c87e56e1..72e83a6b 100644 --- a/app/views/projects/new.html.erb +++ b/app/views/projects/new.html.erb @@ -65,63 +65,117 @@ " >
- <%= form_with url: course_projects_path(@course), method: :post, class: "space-y-8" do |form| %> + <%= form_with url: course_projects_path(@course), method: :post, class: "space-y-8", + data: { controller: "proposal-selection" } do |form| %> + + <%= form.hidden_field :lecturer_id, + value: @selected_lecturer&.id, + id: "hidden_lecturer_id", + data: { proposal_selection_target: "hiddenLecturerId" } %> + + <%= form.hidden_field :based_on_topic, + value: @selected_topic&.id, + id: "hidden_topic_id", + data: { proposal_selection_target: "hiddenTopicId" } %> <%# Reusable input class definition %> <% input_classes = "w-full px-4 py-3 border border-gray-200 rounded-lg sm:rounded-xl text-gray-700 bg-gray-50 focus:outline-none focus:ring-4 focus:ring-blue-500/10 focus:border-blue-500 transition-all font-medium placeholder-gray-400 text-sm sm:text-base" %> <%# Based on topic or lecturer%> -
+
+ +

+ Choose one option below to start your proposal. +

<%# Based on lecturer %> -
-
-
- - - -
-
-

Choose a Lecturer

-

Submit your proposal to a lecturer.

+
+ +
+ +
+
+ + + +
+
+

Choose a Lecturer

+

Submit your proposal directly to a lecturer.

+
+ + <% if @selected_lecturer %> + + <% end %>
    <% @lecturers.each do |lecturer| %> <% capacity_info = @lecturer_capacity_info[lecturer.id] %> <% is_full = capacity_info[:is_at_capacity] %> + <% is_selected = @selected_lecturer&.id == lecturer.id %>
  • -
  • <% end %>
+
<%# OR divider %> @@ -132,51 +186,78 @@
<%# --- Based on topic --- %> -
-
-
- - - -
-
-

Topic

-

- <% if @selected_topic %> - This topic and its details have been pre-filled below. - <% else %> - Choosing a topic will autofill that topic's details. +

+ +
+
+
+
+ + + +
+ +
+

Topic

+ + <% if @selected_topic %> +

+ This topic and its details have been pre-filled below. +

+ <% else %> +

+ Warning: + Selecting a topic will overwrite any details already filled in. +

+ <% end %> +
+
+ + <% if @selected_topic %> +
+ <%= link_to new_course_project_path(@course), + class: "inline-flex shrink-0 items-center gap-1.5 px-4 py-2 text-xs font-semibold text-red-600 bg-white border border-red-200 rounded-lg hover:bg-red-50 hover:border-red-300 transition-colors shadow-sm" do %> + Unselect topic + + + + <% end %> + + <%= link_to course_topics_path(@course, from_new_project: true), + onclick: "return confirm('You\\'ll lose your current form data. Continue?');", + class: "inline-flex shrink-0 items-center gap-1.5 px-4 py-2 text-xs font-semibold text-gray-700 bg-white border border-gray-200 rounded-lg hover:bg-gray-100 transition-colors shadow-sm" do %> + Change topic + + + + <% end %> + +
+ <% else %> + <%= link_to course_topics_path(@course, from_new_project: true), + class: "inline-flex shrink-0 items-center gap-1.5 px-4 py-2 text-xs font-semibold text-gray-700 bg-white border border-gray-200 rounded-lg hover:bg-gray-100 transition-colors shadow-sm" do %> + View all topics + + + <% end %> -

+ <% end %>
-
- <% if @selected_topic %> -
- <%= render "courses/topic_card", topic: @selected_topic %> -
- <%= link_to course_topics_path(@course, from_new_project: true), - class: "mt-3 inline-block text-xs text-blue-600 hover:underline" do %> - Change topic + <%# Selected topic card %> + <% if @selected_topic %> +
+ <%= render "courses/topic_card", topic: @selected_topic %> +
+ <% end %> - <%= form.hidden_field :topic_id, value: @selected_topic.id %> - <% else %> -
-

- Warning: - Choosing a topic will overwrite any details already filled in. -

- <%= link_to course_topics_path(@course, from_new_project: true), - class: "inline-flex items-center gap-1.5 px-4 py-2 text-xs font-semibold text-gray-700 bg-white border border-gray-200 rounded-lg hover:bg-gray-100 transition-colors shrink-0 shadow-sm" do %> - View all topics - - - - <% end %> -
- <% end %> +
+
+ <%= render 'project_new', template_fields: @template_fields, field_values: @field_values, diff --git a/db/seeds.rb b/db/seeds.rb index e4d8d0e6..79ec21d4 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -473,12 +473,6 @@ ) # Create Project Template Fields -title_field_individual = ProjectTemplateField.create!( - project_template: individual_template, - field_type: :shorttext, - applicable_to: :both, - label: 'Project Title' -) project_description_field = ProjectTemplateField.create!( project_template: individual_template, @@ -496,13 +490,6 @@ hint: 'Provide feedback on the proposal' ) -title_field_group = ProjectTemplateField.create!( - project_template: group_template, - field_type: :shorttext, - applicable_to: :both, - label: 'Project Title' -) - group_description_field = ProjectTemplateField.create!( project_template: group_template, field_type: 1, # textarea @@ -511,6 +498,10 @@ hint: 'Describe the group project scope and member responsibilities' ) +# Title fields are auto created via validation callback +title_field_individual = individual_template.project_template_fields.find_by(label: 'Project Title') +title_field_group = group_template.project_template_fields.find_by(label: 'Project Title') + # Create Projects lecturer_1_topic_1 = Topic.create!( course: course_with_groups, @@ -1014,145 +1005,147 @@ value: 'Praesent ultrices ipsum nec ante lobortis feugiat. Vivamus auctor ex eget lobortis cursus' ) -ProjectInstanceField.create!(instance: lecturer_1_topic_1_instance_1, - project_template_field: title_field_individual, - value: 'Difficult Topic 1') +ProjectInstanceField.create!( + instance: lecturer_1_topic_1_instance_1, + project_template_field: title_field_group, + value: 'Difficult Topic 1' +) ProjectInstanceField.create!( instance: lecturer_1_topic_1_instance_1, - project_template_field: project_description_field, + project_template_field: group_description_field, value: 'Sed ut vulputate neque' ) ProjectInstanceField.create!( instance: lecturer_1_topic_2_instance_1, - project_template_field: title_field_individual, + project_template_field: title_field_group, value: 'Difficult Topic 2' ) ProjectInstanceField.create!( instance: lecturer_1_topic_2_instance_1, - project_template_field: project_description_field, + project_template_field: group_description_field, value: 'Donec luctus sem tellus, ac sagittis urna suscipit non.' ) ProjectInstanceField.create!( instance: lecturer_1_topic_3_instance_1, - project_template_field: title_field_individual, + project_template_field: title_field_group, value: 'Difficult Topic 3' ) ProjectInstanceField.create!( instance: lecturer_1_topic_3_instance_1, - project_template_field: project_description_field, + project_template_field: group_description_field, value: 'Etiam mollis risus nec dolor faucibus, lacinia consectetur quam semper' ) ProjectInstanceField.create!( instance: lecturer_1_topic_4_instance_1, - project_template_field: title_field_individual, + project_template_field: title_field_group, value: 'Difficult Topic 4' ) ProjectInstanceField.create!( instance: lecturer_1_topic_4_instance_1, - project_template_field: project_description_field, + project_template_field: group_description_field, value: 'Duis quis sagittis libero' ) ProjectInstanceField.create!( instance: lecturer_2_topic_1_instance_1, - project_template_field: title_field_individual, + project_template_field: title_field_group, value: 'Difficult Topic 1 Lecturer 2' ) ProjectInstanceField.create!( instance: lecturer_2_topic_1_instance_1, - project_template_field: project_description_field, + project_template_field: group_description_field, value: 'Etiam eleifend sodales tincidunt' ) ProjectInstanceField.create!( instance: lecturer_2_topic_2_instance_1, - project_template_field: title_field_individual, + project_template_field: title_field_group, value: 'Difficult Topic 2 Lecturer 2' ) ProjectInstanceField.create!( instance: lecturer_2_topic_2_instance_1, - project_template_field: project_description_field, + project_template_field: group_description_field, value: 'In in auctor ante.' ) ProjectInstanceField.create!( instance: lecturer_2_topic_3_instance_1, - project_template_field: title_field_individual, + project_template_field: title_field_group, value: 'Difficult Topic 3 Lecturer 2' ) ProjectInstanceField.create!( instance: lecturer_2_topic_3_instance_1, - project_template_field: project_description_field, + project_template_field: group_description_field, value: 'Donec mattis sed ex eget aliquet' ) ProjectInstanceField.create!( instance: lecturer_2_topic_4_instance_1, - project_template_field: title_field_individual, + project_template_field: title_field_group, value: 'Difficult Topic 4 Lecturer 2' ) ProjectInstanceField.create!( instance: lecturer_2_topic_4_instance_1, - project_template_field: project_description_field, + project_template_field: group_description_field, value: 'Vivamus tempor lacus consectetur magna laoreet dictum' ) ProjectInstanceField.create!( instance: lecturer_3_topic_1_instance_1, - project_template_field: title_field_individual, + project_template_field: title_field_group, value: 'Difficult Topic 1 Lecturer 3' ) ProjectInstanceField.create!( instance: lecturer_3_topic_1_instance_1, - project_template_field: project_description_field, + project_template_field: group_description_field, value: 'Aenean accumsan vehicula ex eget aliquam.' ) ProjectInstanceField.create!( instance: lecturer_3_topic_2_instance_1, - project_template_field: title_field_individual, + project_template_field: title_field_group, value: 'Difficult Topic 2 Lecturer 3' ) ProjectInstanceField.create!( instance: lecturer_3_topic_2_instance_1, - project_template_field: project_description_field, + project_template_field: group_description_field, value: 'Ut tincidunt cursus nisi eget semper' ) ProjectInstanceField.create!( instance: lecturer_3_topic_3_instance_1, - project_template_field: title_field_individual, + project_template_field: title_field_group, value: 'Difficult Topic 3 Lecturer 3' ) ProjectInstanceField.create!( instance: lecturer_3_topic_3_instance_1, - project_template_field: project_description_field, + project_template_field: group_description_field, value: 'Nullam vitae ornare ex' ) ProjectInstanceField.create!( instance: lecturer_3_topic_4_instance_1, - project_template_field: title_field_individual, + project_template_field: title_field_group, value: 'Difficult Topic 4 Lecturer 3' ) ProjectInstanceField.create!( instance: lecturer_3_topic_4_instance_1, - project_template_field: project_description_field, + project_template_field: group_description_field, value: 'Quisque efficitur magna nec eros luctus, at vestibulum ipsum rutrum.' ) @@ -1295,7 +1288,7 @@ ) ProjectInstanceField.create!( - instance: lecturer_3_topic_1_instance_1, + instance: lecturer_3_topic_1_no_groups_instance_1, project_template_field: lecturer_feedback_field, value: 'Donec a cursus purus' ) From fa27996cc479209c92c3a59e8d762688b268002e Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 11 Apr 2026 11:19:53 +0800 Subject: [PATCH 3/3] fix: removed extra end in projects controller --- app/controllers/projects_controller.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 23a28998..cdab5824 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -274,7 +274,6 @@ def update @project.update!(enrolment: supervisor_enrolment) end - end rescue StandardError => e redirect_to course_project_path(@course, @project), alert: "Project update failed: #{e.message}" return