在Ruby on Rails中导入CSV文件时,无法将数据保存到数据库。

问题描述 投票:0回答:1

我一直在尝试在我的Ruby on Rails应用程序上导入一个.csv文件,以便存储有关峰值的数据,但使用不同的方法都失败了。应用程序重定向到root_url,但数据库仍然是空的。该程序似乎可以工作,至少它没有提供错误,但没有数据被导入数据库。这是我的peaks_controller的样子。

class PeaksController < ApplicationController

    def show
        @peak = Peak.find(params[:id])
    end

    def index
        @peaks = Peak.all
    end

    def import
        Peak.import(params[:file])
        redirect_to root_url, notice: "Peaks imported."

    end

    def new
        @peak = Peak.new
    end

    def create
        @peak = Peak.new(peak_params)

        if @peak.save
            redirect_to @peak
        else
            render 'new'
        end
    end

    def destroy
    end



    private
        def peak_params
            params.require(:peak).permit(:name, :altitude, :prominence, :isolation, :key_col, :source, :accessibility, :land_use, :hazard, :longitude, :latitude)
        end
end

这是我的peak. rb类

class Peak < ApplicationRecord


validates :altitude, presence: true
validates :prominence, presence: true
validates :isolation, presence: true
validates :key_col, presence: true
validates :source, presence: true
validates :accessibility, presence: true
validates :land_use, presence: true

validates :longitude, presence: true
validates :latitude, presence: true



#non funziona

def self.import(file)

    csv = CSV.parse(File.read(file), :headers => true)
    csv.each do |row|

    p = Peak.new


    p.id = row['id'] 
    p.name = row['Name']
    p.altitude = row['Altitude']
    p.prominence = row['Prominence']
    p.isolation = row['Isolation']
    p.key_col = row['Key_col']
    p.source = row['Source']
    p.accessibility = row['Accessibility']
    p.land_use = row['Land_use']
    p.hazard = row['Hazard']
    p.longitude = row['x']
    p.latitude = row['y']
    p.save
    end
end

end

它没有返回任何东西 所以它没有把任何东西导入我的数据库 我也试过下面的导入方法:

def self.import(file)

    csv = CSV.parse(File.read(file), :headers => false)
    csv.each do |row|

    Peak.create!(row.to_h)
    end
end

这是我的数据库的样子

    class CreatePeaks < ActiveRecord::Migration[6.0]
  def change
    create_table :peaks do |t|
        t.string :name
        t.decimal :altitude
        t.decimal :prominence
        t.decimal :isolation
        t.decimal :key_col
        t.string :source
        t.decimal :accessibility
        t.string :land_use
        t.string :hazard
        t.decimal :longitude
        t.decimal :latitude
    end
  end

end

[而这是.csv文件的标题][:1]

我在application.rb中加入了 "require 'csv'",这样应用程序就能读取csv文件。

我也试着从文件中删除 "id "列,并尝试使用 "row.to_h",但没有任何改变,仍然不能将值导入数据库。

你有什么建议吗?

ruby-on-rails ruby csv
1个回答
0
投票

在做大规模导入时,最困难的部分是错误处理--你没有做任何处理。因此,所有这些保存记录的调用都可能失败,而你却毫无察觉。

你基本上有两个选择。

1. 严格的

将导入工作包在一个事务中,如果有任何记录无效,就回滚。这样可以避免工作半途而废。

class Peak < ApplicationRecord
  # ...
  def self.import(file)  
    csv = CSV.parse(File.read(file), :headers => true)
    transaction do
      csv.map do |row|
        create!(
          id: row['id'],
          name: row['Name'],
          altitude: row['Altitude'],
          prominence: row['Prominence'],
          isolation: row['Isolation'],
          key_col: row['Key_col'],
          source: row['Source'],
          accessibility: row['Accessibility'],
          land_use: row['Land_use'],
          hazard: row['Hazard'],
          longitude: row['x'],
          latitude: row['y']
        )
      end
    end
  end
end
class PeaksController < ApplicationController
  def import
    begin 
      @peaks = Peak.import(params[:file])
      redirect_to root_url, notice: "Peaks imported."
    rescue ActiveRecord::RecordInvalid
      redirect_to 'somewhere/else', error: "Import failed."
    end
  end
end

2. 涣散

在某些情况下,你可能想做宽松的处理,即使有些记录未能导入,也要继续下去。这可以结合一个表单,让用户纠正无效值。

class Peak < ApplicationRecord
  # ...
  def self.import(file)  
    csv = CSV.parse(File.read(file), :headers => true)
    peaks = csv.map do |row|
      create_with(
        name: row['Name'],
        altitude: row['Altitude'],
        prominence: row['Prominence'],
        isolation: row['Isolation'],
        key_col: row['Key_col'],
        source: row['Source'],
        accessibility: row['Accessibility'],
        land_use: row['Land_use'],
        hazard: row['Hazard'],
        longitude: row['x'],
        latitude: row['y']
      ).find_or_create_by(id: row['id'])
    end
  end
end
class PeaksController < ApplicationController
  def import
    @peaks = Peak.import(params[:file])
    @invalid_peaks = @peaks.reject {|p| p.persisted? }
    if @invalid_peaks.none?
      redirect_to root_url, notice: "Peaks imported."
    else
      flash.now[:error] = "import failed"
      render 'some_kind_of_form'
    end
  end
end
© www.soinside.com 2019 - 2024. All rights reserved.