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

使用accepts_nested_attributes_for遇ActiveRecord::AssociationTypeMismatch错误求助

Hey there! Let's figure out why you're hitting that ActiveRecord::AssociationTypeMismatch error and fix it up.

What's causing the issue?

The core problem is conflicting association setups:

  • Your User model declares a plain has_one :email, which tells Rails to look for an email record tied to the user via a user_id column.
  • But your Email model uses a polymorphic belongs_to :contactable, which relies on contactable_id and contactable_type columns instead.

When you try to create a user with nested email attributes, Rails gets confused—it tries to assign the User to an email association that doesn't align with the polymorphic contactable setup, hence the type mismatch.

Plus, your original setup doesn't distinguish between the primary login email (one per user) and contact emails (multiple per user), which is critical for your use case.

Step-by-Step Fix

1. Add a flag to distinguish primary vs contact emails

First, we need a way to mark which email is the user's login account. Generate a migration to add an is_primary boolean column to the emails table:

rails generate migration AddIsPrimaryToEmails is_primary:boolean

Run the migration:

rails db:migrate

(You can set a default value of false in the migration if you want, just add default: false to the column definition.)

2. Update your model associations

Adjust the User model to explicitly define the two types of email relationships, and tie them to the polymorphic contactable association in Email:

class User < ApplicationRecord
  has_secure_password

  # Primary login email (one per user, marked as primary)
  has_one :primary_email, 
          -> { where(is_primary: true) }, 
          class_name: "Email", 
          as: :contactable, 
          dependent: :destroy

  # Contact emails (multiple per user, non-primary)
  has_many :contact_emails, 
           -> { where(is_primary: false) }, 
           class_name: "Email", 
           as: :contactable, 
           dependent: :destroy

  # Allow nested creation of the primary email
  accepts_nested_attributes_for :primary_email
end

Update the Email model to enforce uniqueness of primary emails per user, and remove the unnecessary accepts_nested_attributes_for :contactable (since we're creating emails from the user side, not the other way around):

class Email < ApplicationRecord
  belongs_to :contactable, polymorphic: true
  validates :email, presence: true, uniqueness: true
  # Ensure only one primary email per user
  validates :is_primary, uniqueness: { scope: :contactable_id }, if: -> { is_primary }
end

3. Fix your controller's create logic

Update your user_controller.rb to handle the nested primary email attributes, and ensure the is_primary flag is set to true for the login email:

class UsersController < ApplicationController
  def create
    @user = User.new(user_params)
    
    # Ensure the primary email is marked as such
    if @user.primary_email_attributes.present?
      @user.primary_email_attributes[:is_primary] = true
    end

    if @user.save
      redirect_to @user, notice: 'User created successfully!'
    else
      render :new
    end
  end

  private

  def user_params
    params.require(:user).permit(
      :name, 
      :password, 
      :password_confirmation, 
      primary_email_attributes: [:email] # is_primary is set in the controller
    )
  end
end

Why this works

  • We've clearly separated the primary login email from contact emails using the is_primary flag.
  • The associations now correctly use the polymorphic contactable setup, so Rails knows how to tie users to their emails without conflicting column expectations.
  • The validation ensures no user can have more than one primary login email, which aligns with your requirement.

内容的提问来源于stack exchange,提问作者Pavel Perevezencev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:02:34