Rescuing validation errors from a polymorphic association

55 views Asked by At

Having an issue with updating nested attributes for a polymorphic association, specifically, when attempting to update nested records through a join model.

The nested records can be one of a dozen different models and are known simply to the join model as "component". My error messages correctly indicate the attribute that failed validation but the message identifies the record as "component": "Validation failed: Page components component alt text can't be blank"

Here are my relationship configurations:

class Page < ApplicationRecord
    has_many :page_components, -> { order(position: :asc) }, dependent: :destroy, autosave: true
    accepts_nested_attributes_for :page_components, allow_destroy: true
    ...
end

class PageComponent < ApplicationRecord
    belongs_to :page, optional: trueacts_as_list scope: :page
    belongs_to :component, polymorphic: true, autosave:  true
    accepts_nested_attributes_for :component
    ...
end

class PageImageComponent < ApplicationRecord
    has_one :page_component, as: :component, autosave: true
    ...
end

In the error message, Page is correctly identified as the parent but what I'm hoping for is to identify which type of association failed validation. So if the component is a PageImageComponent the message would ideally read "Validation failed: Page components page_image_component alt text can't be blank". Or something like that

Is this just not possible? I would think if it can identify the attribute it should have access to the class name as well..

update:

where this is happening is a simple record update:

@page.update!(permitted_params[:page])

where permitted_params would be:

#<ActionController::Parameters {"title"=>"test 1", "page_group_id"=>"4", "description"=>"test page description", "is_visible"=>"1", "is_public"=>"1", "template_type"=>"default", "has_chrome_warning_banner"=>"0", "image_alt_text"=>"", "page_components_attributes"=>#<ActionController::Parameters {"0"=>#<ActionController::Parameters {"id"=>"14", "component_type"=>"PageImageComponent", "position"=>"1", "_destroy"=>"0", "component_attributes"=>#<ActionController::Parameters {"url"=>"/about", "alignment"=>"center", "alt_text"=>""} permitted: true>} permitted: true>} permitted: true>} permitted: true>

rescue block:

rescue => e
        respond_to do |format|
          if params[:action] === 'update'
            format.html { redirect_to edit_admin_page_path(@page), flash: { error:  "#{e.message}"} }
          else
            format.html { redirect_to new_admin_page_path, flash: { error:  "#{e.message}"} }
          end
        end
1

There are 1 answers

2
peresvetjke On

I would think if it can identify the attribute it should have access to the class name as well..

Human attribute names are defined on class level. So by default it knows nothing about params you pass (while your association is polymorphic and types may vary).

what I'm hoping for is to identify which type of association failed validation.

You can add validates_associated method in PageComponent class with a message option:

class PageComponent < ApplicationRecord
  belongs_to :page, optional: trueacts_as_list scope: :page
  belongs_to :component, polymorphic: true, autosave:  true
  accepts_nested_attributes_for :component

  validates_associated :component, message: ->(_base, options) {
    "(#{options[:value].class}) is invalid."
  }
end

I would also consider custom validator for Page model where I could get full error messages I want including positions of failed components which might by useful as well.