You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ActiveAdmin中多态关联Tag模型表单名称映射问题求助

Fixing Polymorphic Association Display & Saving in ActiveAdmin Tag Form

I get exactly what you're dealing with here—your current code passes plain string names (nicknames/activity names) to the taggable input, but ActiveAdmin needs the actual polymorphic identifiers (taggable_type and taggable_id) to save the association properly. That's why you're hitting the "must exist and can't be blank" error.

Here's a clean solution that uses the label_method/value_method pattern you wanted, letting you show friendly names while ensuring the association saves correctly:

Step 1: Update the Form Input

Modify your taggable input to combine both models in the collection, use a dynamic label to show the right name, and pass a structured value that captures both the model type and ID:

ActiveAdmin.register Tag do
  permit_params :name, :taggable # We'll handle type/id in the controller
  # ...

  form do |f|
    f.semantic_errors
    f.inputs do
      f.input :name, collection: Tag::TAG_NAMES
      # Remove the separate taggable_type input—we'll derive it from the selected option
      f.input :taggable, label: "Account / Activity", 
              collection: Account.all + Activity.all,
              label_method: ->(obj) { 
                # Show nickname for Accounts, name for Activities
                obj.is_a?(Account) ? obj.nickname : obj.name 
              },
              value_method: ->(obj) { 
                # Pass a string combining class name and ID, e.g., "Account:123"
                "#{obj.class.name}:#{obj.id}" 
              }
    end
    f.actions
  end

Step 2: Add Controller Logic to Parse Polymorphic Values

We need to take the combined string from the form, split it into taggable_type and taggable_id, and assign those fields before saving. Add this controller block to your ActiveAdmin registration:

controller do
    def create
      parse_taggable_params
      super
    end

    def update
      parse_taggable_params
      super
    end

    private

    def parse_taggable_params
      return unless params[:tag][:taggable].present?
      
      # Split the structured value into model type and ID
      taggable_type, taggable_id = params[:tag][:taggable].split(':')
      
      # Assign the required polymorphic fields
      params[:tag][:taggable_type] = taggable_type
      params[:tag][:taggable_id] = taggable_id
      
      # Remove the temporary taggable parameter—we don't need it anymore
      params[:tag].delete(:taggable)
    end
  end
end

Why This Works

  • label_method: Dynamically displays the nickname for Accounts and name for Activities, making the dropdown user-friendly instead of showing raw instance strings.
  • value_method: Passes a structured string that holds both the model class and ID, which we can parse into the exact fields your Tag model expects.
  • Controller Logic: Converts the structured input value into the taggable_type and taggable_id fields, ensuring the association is saved correctly without validation errors.

Optional: Add Type Context to Labels

If you have Accounts and Activities with identical names, add the model type to the label to avoid confusion:

label_method: ->(obj) { 
  "#{obj.class.name}: #{obj.is_a?(Account) ? obj.nickname : obj.name}" 
}

内容的提问来源于stack exchange,提问作者Antoine Quellier

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 03:49:39