Rails应用程序中的关联类型不匹配

时间:2017-11-14 01:36:28

标签: ruby-on-rails activerecord

Rails 5.1

我的迁移文件:

class CreateFwExports < ActiveRecord::Migration[5.1]
  def change
    create_table :fw_exports, id: :string do |t|
      t.string :screen_name, index: true, limit: 16
      t.string :full_name, limit: 21
      t.string :location

      t.timestamps
    end

  end
end

在我的帮助文件中,我有以下方法:

def process_spreadsheet(number_of_rows, spreadsheet)
  for i in 1..number_of_rows do
    fw_export_record = FwExport.new(
        :screen_name => spreadsheet[i][0].to_s,
        :full_name => spreadsheet[i][1].to_s,
        :location => spreadsheet[i][2].to_s,
    )
    fw_export_record.save
  end
end 

此方法的作用是接收电子表格CSV对象,并迭代数据,尝试将每一行保存到fw_exports表。

第一个数据行是:

xxxxxxxx,xxxxxxxxxx,"Nottingham, England"

我收到以下错误消息:

ActiveRecord::AssociationTypeMismatch (Location(#38400060) expected, got "Nottingham, England" which is an instance of String(#10657520)):
app/helpers/fw_exports_helper.rb:21:in `block in process_spreadsheet'
app/helpers/fw_exports_helper.rb:20:in `process_spreadsheet'
app/controllers/fw_exports_controller.rb:82:in `process_parsed_spreadsheet'

当我查看实际的MySQL表时,这是我得到的:

id Primary  varchar(255)    utf8mb4_unicode_ci      No  None
screen_name  varchar(16)    utf8mb4_unicode_ci      Yes NULL
full_name   varchar(21) utf8mb4_unicode_ci      Yes NULL
location    varchar(255)    utf8mb4_unicode_ci      Yes NULL

来自控制器:

def fw_export_params
  params.require(:fw_export).permit(:screen_name, :full_name, :location)
end 

id是通过关注部分

中定义的方法生成的

知道我为什么收到错误消息?

编辑:

在我的fw_exports.rb模型中,我有以下内容:

has_one :location

我有一个位置表(和模型),包含以下字段:

  t.string :fw_exports_id, index: true
  t.string :city
  t.string :state
  t.string :country

当我注释掉时,fw_exports.rb模型中的行:

# has_one :location

我停止了上面提到的错误,相反,我现在收到以下错误:

NoMethodError (undefined method `each' for "0":String):
app/helpers/fw_exports_helper.rb:21:in `block in process_spreadsheet'
app/helpers/fw_exports_helper.rb:20:in `process_spreadsheet'
app/controllers/fw_exports_controller.rb:82:in `process_parsed_spreadsheet'

代码中的相同位置,不同的消息。

2 个答案:

答案 0 :(得分:1)

在执行

之后添加|i|
for i in 1..number_of_rows do |i|

在评论回复后编辑: 您没有显示模型,但可能有一个名为location的关系与该字段冲突。

答案 1 :(得分:0)

正如你所说:

class FwExport < ApplicationRecord
  has_one :location

并假设:

class Location < ApplicationRecord
  belongs_to :fw_export

因此您无法将:location定义为CreateFwExports迁移中的字符串列。

首先,您需要编写另一个迁移来从:fw_exports表中删除列:

class RemoveColumnFromFwExports < ActiveRecord::Migration[5.1]
  def change
    remove_column :fw_exports, :location, :string
  end
end

现在重写帮助方法,该方法将位置字符串从csv解析为Location实例并将其分配到FwExport实例中:

def process_spreadsheet(number_of_rows, spreadsheet)
  1.upto(number_of_rows) do |i|
    fw_export_record = FwExport.new(
        screen_name: spreadsheet[i][0].to_s,
        full_name: spreadsheet[i][1].to_s,
    )
    fw_export_record.save

    # now create the location and associate it to fw_export_record
    location = find_or_create_location(spreadsheet[i][2].to_s)
    location.fw_exports_id = fw_export_record.id
    location.save
  end
end

private

def find_or_create_location(s)
  city, country = s.split(',').map(&:strip)
  Location.find_or_create_by!(city: city, country: country)
end