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

时间:2017-08-19 22:17:34

标签: ruby-on-rails relational-database

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

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

地址' model与地址线有一对多的关系'模型,以及相应的'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

当我运行Rails控制台时,我收到以下错误,指的是&#34; acondigitaladdresslineone = ...&#34;代码行:

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

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

# 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"

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

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

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

我需要进行健全检查。这是一个合理的假设,为什么&#39; AssociationTypeMismatch&#39;错误被提出了?

谢谢。

1 个答案:

答案 0 :(得分:1)

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

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

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

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

class Addressline
  belongs_to :address 
end

这样做的原因是:

Addressline.new(address: 'Foo')

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

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

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