为什么我收到'AssociationTypeMismatch'错误?

时间:2020-12-08 22:50:16

I have the following code in my Rails 'seeds.rb' file:

我在Rails的seeds.rb'文件中有以下代码:

acondigitaladdresslineone = Addressline.create!(address_id: acondigitaladdress.id, address: "Sørkedalsveien 273", address_line_position: 0)

The 'Address' model has a one-to-many relation with the 'Addressline' model, and the respective 'belongs_to' and 'has_many' declarations are properly in place. Here is the content of the migration files:

“地址”模型与“地址线”模型具有一对多关系,并且相应的“belongs_to”和“has_many”声明已正确到位。以下是迁移文件的内容:

class CreateAddresses < ActiveRecord::Migration[5.0]
  def change
    create_table :addresses do |t|
      t.references :towncity, foreign_key: true
      t.references :stateregion, foreign_key: true, null: true
      t.references :postalcode, foreign_key: true

      t.timestamps
    end
  end
end

class CreateAddresslines < ActiveRecord::Migration[5.0]
  def change
    create_table :addresslines do |t|
      t.references :address, foreign_key: true
      t.string :address
      t.integer :address_line_position

      t.timestamps
    end
  end
end

When I run the Rails Console, I receive the following error, which refers to the "acondigitaladdresslineone = ..." line of code:

当我运行Rails控制台时,我收到以下错误,它引用了“acondigitaladdresslineone = ...”代码行:

ActiveRecord::AssociationTypeMismatch: Address(#8269560) expected, got String(#6922340)

I corrected the error by making the following changes:

我通过进行以下更改来纠正错误:

# From the 'CreateAddresslines' migration file

    # Original code
    t.string :address

    # Revised code
    t.string :address_name

# From the 'acondigitaladdresslineone' variable declaration line

    # Original code
    address: "Sørkedalsveien 273"

    # Revised code
    address_name: "Sørkedalsveien 273"

I suspect the cause of the error possibly is due the underlying database's (in this case SQLite) inability to disambiguate the same field name based upon datatype. For example, in the original version of the 'CreateAddresslines' migration file, SQLlite raises an error as a result of these two declarations:

我怀疑错误的原因可能是由于底层数据库(在本例中为SQLite)无法根据数据类型消除相同字段名称的歧义。例如,在“CreateAddresslines”迁移文件的原始版本中,SQLlite会因这两个声明而引发错误:

t.references :address, foreign_key: true
t.string :address

It is easy to overlook the obvious when entangled in coding. Clearly, a relational database table cannot have two or more columns with the same name. I am unaware of any relational database management system having a capability to disambiguate same-named table columns based upon differences in their datatypes.

当纠缠于编码时,很容易忽略这一点。显然,关系数据库表不能包含两个或多个具有相同名称的列。我不知道任何关系数据库管理系统能够根据其数据类型的差异消除同名表列的歧义。

I need a sanity check. Is this a reasonable assumption why the 'AssociationTypeMismatch' error was raised?

我需要进行健全检查。这是一个合理的假设,为什么会出现'AssociationTypeMismatch'错误?

Thank you.

谢谢。

1 个解决方案

#1


1  

t.references :address will create the column address_id so there should be no conflict with t.string :address on the DB level.

t.references:address将创建列address_id,因此在数据库级别上不应与t.string:address冲突。

The problem occurs in ActiveRecord when accessors and associations are declared.

声明访问器和关联时,ActiveRecord中会出现此问题。

ActiveRecord reads the schema from the database and uses it to create attributes and accessor methods in your models for each column. This happens before any of the code in the class declaration block is evaluated.

ActiveRecord从数据库中读取模式,并使用它在模型中为每列创建属性和访问器方法。这是在评估类声明块中的任何代码之前发生的。

When you then create an association you are overwriting the #address and #address= methods created for the string attribute.

然后,当您创建关联时,您将覆盖为字符串属性创建的#address和#address =方法。

class Addressline
  belongs_to :address 
end

Which is why when you do:

这样做的原因是:

Addressline.new(address: 'Foo')

You get a type error since the #address= setter method is setting address_id and expects an Address instance.

您收到类型错误,因为#address = setter方法正在设置address_id并且需要一个Address实例。

The solution is as you might have surmised is to not name other columns the same thing as your associations. Just rename the column:

您可能已经推测的解决方案是不将其他列命名为与关联相同的内容。只需重命名列:

class FixColumnName < ActiveRecord::Migration
  def self.change
    # call it whatever you want, but not address!
    rename_column :addresslines, :address, :value
  end
end

#1


1  

t.references :address will create the column address_id so there should be no conflict with t.string :address on the DB level.

t.references:address将创建列address_id,因此在数据库级别上不应与t.string:address冲突。

The problem occurs in ActiveRecord when accessors and associations are declared.

声明访问器和关联时,ActiveRecord中会出现此问题。

ActiveRecord reads the schema from the database and uses it to create attributes and accessor methods in your models for each column. This happens before any of the code in the class declaration block is evaluated.

ActiveRecord从数据库中读取模式,并使用它在模型中为每列创建属性和访问器方法。这是在评估类声明块中的任何代码之前发生的。

When you then create an association you are overwriting the #address and #address= methods created for the string attribute.

然后,当您创建关联时,您将覆盖为字符串属性创建的#address和#address =方法。

class Addressline
  belongs_to :address 
end

Which is why when you do:

这样做的原因是:

Addressline.new(address: 'Foo')

You get a type error since the #address= setter method is setting address_id and expects an Address instance.

您收到类型错误,因为#address = setter方法正在设置address_id并且需要一个Address实例。

The solution is as you might have surmised is to not name other columns the same thing as your associations. Just rename the column:

您可能已经推测的解决方案是不将其他列命名为与关联相同的内容。只需重命名列:

class FixColumnName < ActiveRecord::Migration
  def self.change
    # call it whatever you want, but not address!
    rename_column :addresslines, :address, :value
  end
end