ActiveRecord :: AssociationTypeMismatch Rails CSV Import - PullRequest
0 голосов
/ 26 сентября 2019

Я использую gem roo для импорта данных CSV.Это работает гладко, до точки, где есть ассоциация, и я надеюсь, что roo может преобразовать строку в соответствующее целочисленное значение в ассоциации.В моем случае у меня есть модель Staff, которая принадлежит State.

class State < ApplicationRecord
    has_many :staffs

end
class Staff < ApplicationRecord
    belongs_to :state

end

Это означает, что у меня есть столбец state_id в таблице staffs.В моем CSV, однако, у конечного пользователя есть имена состояний, которые соответствуют тем в таблицах states.Когда я пытаюсь импортировать CSV, я получаю сообщение об ошибке:

ActiveRecord::AssociationTypeMismatch in StaffsImportsController#create
State(#134576500) expected, got "Texas" which is an instance of String(#20512180)

Подсвеченный источник:

staff.attributes = row.to_hash

Возможно ли для gem roo перевести «Техас» вCSV-файл, скажем, с идентификатором 2, вместо того, чтобы конечный пользователь выполнял большую работу по переводу перед загрузкой данных?

Вот staffs_imports.rb

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(&:valid?).all?
      imported_staffs.each(&: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

И наконец staff_imports_controller.rb:

class StaffsImportsController < 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

Любая помощь / подсказки будут высоко оценены.

...