EastsideDev
EastsideDev

Reputation: 6659

Association type mismatch in Rails app

Rails 5.1

My migration file:

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

In my helper file, I have the following method:

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 

What this method does, is receive a spreadsheet CSV object, and iterates through the data, trying to save each row to the fw_exports table.

The first data row is:

xxxxxxxx,xxxxxxxxxx,"Nottingham, England"

I am getting the following error message:

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'

When I looked at the actual MySQL table, here's what I got:

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

From the controller:

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

id is generated through a method defined in the concerns section

Any idea why I'm getting the error message?

Edit:

In my fw_exports.rb model, I had the following:

has_one :location

I have a locations table (and model), with the following fields:

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

When I commented out, the line in the fw_exports.rb model:

# has_one :location

I stopped getting the above mentioned error, and instead, I am now getting the following error:

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'

Same spot in code, different message.

Upvotes: 3

Views: 2483

Answers (2)

Wasif Hossain
Wasif Hossain

Reputation: 3960

As you have:

class FwExport < ApplicationRecord
  has_one :location

and assuming that:

class Location < ApplicationRecord
  belongs_to :fw_export

so you cannot define :location as a string column in CreateFwExports migration.

First you need to write another migration to remove the column from :fw_exports table:

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

Now rewrite the helper method that would parse the location string from csv into a Location instance and assign it into the FwExport instance:

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

Upvotes: 0

s1mpl3
s1mpl3

Reputation: 1464

Add |i| after the do

for i in 1..number_of_rows do |i|

Edit after response in comment: You don't show the model but probably you have a relationship called location that is conflicting with the field.

Upvotes: 2

Related Questions