From 836cbe7c560ecdbe7e98c46fc03c0a924975c62e Mon Sep 17 00:00:00 2001 From: nakamura Date: Fri, 28 Feb 2025 06:36:56 +0000 Subject: [PATCH] Add support for custom validation contexts in resource creation and update --- .../administrate/application_controller.rb | 26 ++++++++++++-- docs/customizing_controller_actions.md | 27 +++++++++++++++ .../admin/application_controller_spec.rb | 34 +++++++++++++++++++ 3 files changed, 85 insertions(+), 2 deletions(-) diff --git a/app/controllers/administrate/application_controller.rb b/app/controllers/administrate/application_controller.rb index 905385fad6..72aaaf8dbc 100644 --- a/app/controllers/administrate/application_controller.rb +++ b/app/controllers/administrate/application_controller.rb @@ -58,7 +58,7 @@ def create authorize_resource(resource) end - if resource.save + if resource.save(context: validation_contexts_on_create(resource)) yield(resource) if block_given? redirect_to( after_resource_created_path(resource), @@ -75,7 +75,9 @@ def create def update @resource = resource = requested_resource - if resource.update(resource_params) + resource.assign_attributes(resource_params) + + if resource.save(context: validation_contexts_on_update(resource)) redirect_to( after_resource_updated_path(resource), notice: translate_with_resource("update.success"), @@ -293,6 +295,26 @@ def authorize_resource(resource) end end + # Override this if you want to provide additional validation contexts. + # + # @param resource [ActiveRecord::Base] The resource to be validated. + # @return [Array] The validation contexts to be used. + def validation_contexts_on_create(resource) + default_validation_contexts(resource) + end + + # Override this if you want to provide additional validation contexts. + # + # @param resource [ActiveRecord::Base] The resource to be validated. + # @return [Array] The validation contexts to be used. + def validation_contexts_on_update(resource) + default_validation_contexts(resource) + end + + def default_validation_contexts(resource) + resource.new_record? ? [:create] : [:update] + end + def paginate_resources(resources) resources.page(params[:_page]).per(records_per_page) end diff --git a/docs/customizing_controller_actions.md b/docs/customizing_controller_actions.md index 73d98ca1e6..18bbcd60b2 100644 --- a/docs/customizing_controller_actions.md +++ b/docs/customizing_controller_actions.md @@ -107,3 +107,30 @@ def create end end ``` + +## Validation Contexts + +You can customize the context when saving a resource in the controller. +For example, with the following settings, regular admins are required to input a name, but super admins can update the resource *without* a name. + +```ruby +# Model +validates :name, presence: true, on: :save_by_regular_admin + +# Controller +def validation_contexts_on_create(resource) + if current_user.super_admin? + super + [:save_by_super_admin] + else + super + [:save_by_regular_admin] + end +end + +def validation_contexts_on_update(resource) + if current_user.super_admin? + super + [:save_by_super_admin] + else + super + [:save_by_regular_admin] + end +end +``` diff --git a/spec/controllers/admin/application_controller_spec.rb b/spec/controllers/admin/application_controller_spec.rb index 031a2ad8e5..f4bbab1c36 100644 --- a/spec/controllers/admin/application_controller_spec.rb +++ b/spec/controllers/admin/application_controller_spec.rb @@ -100,4 +100,38 @@ def authorized_action?(resource, _action) .to raise_error(Administrate::NotAuthorizedError) end end + + describe "validation contexts" do + render_views + controller(Admin::ProductsController) do + def validation_contexts_on_create(resource) + super + [:some_unclear_situation] + end + + def validation_contexts_on_update(resource) + super + [:some_unclear_situation] + end + end + + context "on create" do + it "raise a validation error due to custom validation context" do + params = attributes_for(:product) + post :create, params: {product: params} + + expect(response).to have_http_status(:unprocessable_entity) + expect(response.body).to include("Product meta tag can't be blank") + end + end + + context "on update" do + it "raise a validation error due to custom validation context" do + product = create(:product, product_meta_tag: nil) + params = {name: "New Name"} + put :update, params: {id: product.to_param, product: params} + + expect(response).to have_http_status(:unprocessable_entity) + expect(response.body).to include("Product meta tag can't be blank") + end + end + end end