diff --git a/app/models/project.rb b/app/models/project.rb index f8bdd56b03ae..4ecfb916bf09 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -122,6 +122,7 @@ def validation_context @validation_context end end + acts_as_searchable columns: %W(#{table_name}.name #{table_name}.identifier #{table_name}.description), date_column: "#{table_name}.created_at", project_key: "id", diff --git a/spec/features/projects/life_cycle/overview_page/dialog/update_spec.rb b/spec/features/projects/life_cycle/overview_page/dialog/update_spec.rb index 32f433111b29..d0883a150b48 100644 --- a/spec/features/projects/life_cycle/overview_page/dialog/update_spec.rb +++ b/spec/features/projects/life_cycle/overview_page/dialog/update_spec.rb @@ -155,5 +155,24 @@ dialog.expect_closed end end + + context "when there is an invalid custom field on the project (Regression#60666)" do + let(:custom_field) { create(:string_project_custom_field, is_required: true, is_for_all: true) } + + before do + project.custom_field_values = { custom_field.id => nil } + project.save(validate: false) + end + + it "allows saving and closing the dialog without the custom field validation to interfere" do + dialog = overview_page.open_edit_dialog_for_life_cycles + + expect_angular_frontend_initialized + + # Saving the dialog is successful + dialog.submit + dialog.expect_closed + end + end end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 2d3ab1fe2f1b..10d513bd1721 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -455,6 +455,38 @@ it_behaves_like "acts_as_customizable included" do let(:model_instance) { project } let(:custom_field) { create(:string_project_custom_field) } + + describe "valid?" do + let(:custom_field) { create(:string_project_custom_field, is_required: true) } + + before do + model_instance.custom_field_values = { custom_field.id => "test" } + model_instance.save + model_instance.custom_field_values = { custom_field.id => nil } + end + + context "without a validation context" do + it "does not validates the custom fields" do + expect(model_instance).to be_valid + end + + it "does not includes the default validation context in the validation_context" do + model_instance.send(:validation_context=, :custom_context) + expect(model_instance.validation_context).to eq(:custom_context) + end + end + + context "with the :saving_custom_fields validation context" do + it "validates the custom fields" do + expect(model_instance).not_to be_valid(:saving_custom_fields) + end + + it "includes the default validation context too in the validation_context" do + model_instance.send(:validation_context=, :saving_custom_fields) + expect(model_instance.validation_context).to eq(%i(saving_custom_fields update)) + end + end + end end describe "url identifier" do @@ -484,5 +516,30 @@ expect(project.identifier).not_to eq(word) end end + + # The acts_as_url plugin defines validation callbacks on :create and it is not automatically + # called when calling a custom context. However we need the acts_as_url callback to set the + # identifier when the validations are called with the :saving_custom_fields context. + context "when validating with :saving_custom_fields context" do + it "is set from name" do + project = described_class.new(name: "foo") + + project.validate(:saving_custom_fields) + + expect(project.identifier).to eq("foo") + end + + it "is not allowed to clash with projects routing" do + expect(reserved).not_to be_empty + + reserved.each do |word| + project = described_class.new(name: word) + + project.validate(:saving_custom_fields) + + expect(project.identifier).not_to eq(word) + end + end + end end end