title: ActiveRecord::AssociationTypeMismatch Rails CSV Import
body: <p>I am using <code>gem roo</code> to import CSV data. It works smoothly, until the point where there is an association, and am hoping that roo can translate the string into the corresponding integer value in the association. In my case, I have a <code>Staff</code> model which belongs to <code>State</code>.</p>
  
  <pre><code>class State &lt; ApplicationRecord
      has_many :staffs
  
  end
  </code></pre>
  
  <pre><code>class Staff &lt; ApplicationRecord
      belongs_to :state
  
  end
  </code></pre>
  
  <p>This means that I have <code>state_id</code> column in the <code>staffs</code> table. In my CSV, however, the end user has the names of the states, which correspond to the ones in the <code>states</code> tables. When I try to import the CSV, I get the error:</p>
  
  <pre><code>ActiveRecord::AssociationTypeMismatch in StaffsImportsController#create
  State(#134576500) expected, got "Texas" which is an instance of String(#20512180)
  </code></pre>
  
  <p>The highlighted source is:</p>
  
  <pre><code>staff.attributes = row.to_hash
  </code></pre>
  
  <p>Is it possible for <code>gem roo</code> to translate  'Texas' in the csv file to, say, id 2, instead of the end user doing a lot of translation work before uploading the data?</p>
  
  <p>Here is <code>staffs_imports.rb</code></p>
  
  <pre><code>class StaffsImport
    include ActiveModel::Model
    require 'roo'
  
    attr_accessor :file
  
    def initialize(attributes={})
      attributes.each { |name, value| send("#{name}=", value) }
    end
  
    def persisted?
      false
    end
  
    def open_spreadsheet
      case File.extname(file.original_filename)
      when ".csv" then Csv.new(file.path, nil, :ignore)
      when ".xls" then Roo::Excel.new(file.path, nil, :ignore)
      when ".xlsx" then Roo::Excelx.new(file.path)
      else raise "Unknown file type: #{file.original_filename}"
      end
    end
  
    def load_imported_staffs
      spreadsheet = open_spreadsheet
      header = spreadsheet.row(1)
      (2..spreadsheet.last_row).map do |i|
        row = Hash[[header, spreadsheet.row(i)].transpose]
        staff = Staff.find_by_national_id(row["national_id"]) || Staff.new
        staff.attributes = row.to_hash
        staff
      end
    end
  
    def imported_staffs
      @imported_staffs ||= load_imported_staffs
    end
  
    def save
      if imported_staffs.map(&amp;:valid?).all?
        imported_staffs.each(&amp;:save!)
        true
      else
        imported_staffs.each_with_index do |staff, index|
          staff.errors.full_messages.each do |msg|
            errors.add :base, "Row #{index + 6}: #{msg}"
          end
        end
        false
      end
    end
  
  end
  </code></pre>
  
  <p>And finally the <code>staff_imports_controller.rb</code>:</p>
  
  <pre><code>class StaffsImportsController &lt; ApplicationController
  
    def new
      @staffs_import = StaffsImport.new
    end
  
    def create
      @staffs_import = StaffsImport.new(params[:staffs_import])
      if @staffs_import.save
        flash[:success] = "You have successfully uploaded your staff!"
        redirect_to staffs_path
      else
        render :new
      end
    end
  end
  </code></pre>
  
  <p>Any help/clues will be highly appreciated.</p>