我一直在尝试在我的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",但没有任何改变,仍然不能将值导入数据库。
你有什么建议吗?
在做大规模导入时,最困难的部分是错误处理--你没有做任何处理。因此,所有这些保存记录的调用都可能失败,而你却毫无察觉。
你基本上有两个选择。
将导入工作包在一个事务中,如果有任何记录无效,就回滚。这样可以避免工作半途而废。
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
在某些情况下,你可能想做宽松的处理,即使有些记录未能导入,也要继续下去。这可以结合一个表单,让用户纠正无效值。
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