ActiveRecord :: AssociationTypeMismatch with accepts_nested_attributes_for

时间:2018-04-08 14:19:32

标签: ruby-on-rails

我有UserEmail个表,关系一User有一个Email(作为系统中的登录名)。但是,用户可能有许多Emails作为自己的联系人。

class User < ApplicationRecord
  has_secure_password

  has_one :email
  # has_many :phones, as: :contactable

  accepts_nested_attributes_for :email
end

class Email < ApplicationRecord
  belongs_to :contactable, polymorphic: true

  accepts_nested_attributes_for :contactable

  validates :email, presence: true, uniqueness: true
end

user_controller.rb

  def create
    @user = User.new(user_params)

    if @user.save
      render json: @user, except: :password_digest, status: :created, location: @user
    else
      render json: @user.errors, status: :unprocessable_entity
    end
  end

  private
    def user_params
      params.permit(
        :email,
        :password, 
        :first_name, 
        :last_name, 
        :patronymic, 
        email_attributes: [:email]
      )
    end

当我尝试发送此类请求时

{
    "email": "test@test.ru",
    "phone": "+799999999999",
    "password": "test",
    "first_name": "First-name",
    "last_name": "Last-name",
    "patronymic": "Patronymic"
}

我有这个错误

"exception": "#<ActiveRecord::AssociationTypeMismatch: Email(#70266002240460) expected, got \"test@test.ru\" which is an instance of String(#47039052873240)>" 

我做错了什么?

更新

  1. 我用has_one
  2. 替换了belongs_to关系
  3. 并将user_params功能更改为此

    params.permit(:password,:first_name,:last_name,:patronymic,email_attributes:[:email])

  4. 但如果我尝试发布这样的帖子请求:

    {
        "email_attributes": {
            "email": "test@test.ru"
        },
        "phone": "+799999999999",
        "password": "test",
        "first_name": "First-name",
        "last_name": "Last-name",
        "patronymic": "Patronymic"
    }
    

    我有错误

    {
        "email.contactable": [
            "must exist"
        ]
    }
    

    并提出问题:如何摆脱email_attributes?

1 个答案:

答案 0 :(得分:1)

您的用户没有名为email的列,它有一个关联,意图是一个新的电子邮件对象,具有自己的属性。

如果它只是一个专栏,那么你可以让params出现类似:

user: { 
  name: 'Fred', # this is a column on users
  email: 'fred@example.com' # this is another column on users
}

但相反,你需要它像一个单独的模型。现在你的电子邮件模型本身就是一个数据库表,并且有一个列,例如称为'email'吧?如果是这样,那么你需要使用参数来进行这样的事情:

user: { 
  name: 'Fred', # this is a column on users
  email: { # this tells us that it's another object called 'email'
    email: 'fred@example.com' # this is a column on emails
  }
}

显然,您需要重命名列以匹配您自己的列。

我还要指出,在您的许可证中,您既有一封电子邮件作为用户列,也有email_attributes - 其中包含一个名为email的不同关联模型的属性