注意:在我的application.rb文件中,我同时需要csv
和iconv
。
我正在构建一个Ruby on Rails应用程序,以将.xls和.csv文件导入到联系人数据库中。我使用Rails Cast#396作为我的公会,但是由于我使用Rails 4,它有一些问题。
我已经(尽我所能)实现了上传.csv,.xls和.xlsx文件的能力。但是,当我选择.csv文件进行上传时,我收到以下错误和堆栈跟踪:
uninitialized constant Contact::Csv
Rails.root: C:/workspace/contactually-lite
Application Trace | Framework Trace | Full Trace
app/models/contact.rb:18:in `open_spreadsheet'
app/models/contact.rb:6:in `import'
app/controllers/contacts_controller.rb:5:in `import'
这是我的contact.rb文件:
class Contact < ActiveRecord::Base
def self.import(file)
spreadsheet = open_spreadsheet(file)
header = spreadsheet.row(1)
(2..spreadsheet.last_row).each do |i|
row = Hash[[header, spreadsheet.row(i)].transpose]
contact = find_by_id(row["id"]) || new
contact.attributes = row.to_hash.slice(*accessible_attributes)
contact.save!
end
end
def self.open_spreadsheet(file)
case File.extname(file.original_filename)
when ".csv" then Csv.new(file.path, nil, :ignore)
when ".xls" then Excel.new(file.path, nil, :ignore)
when ".xlsx" then Excelx.new(file.path, nil, :ignore)
else raise "Unknown file type: #{file.original_filename}"
end
end
end
这是我的contact_controller.rb
文件:
class ContactsController < ApplicationController
before_action :set_contact, only: [:show, :edit, :update, :destroy]
def import
Contact.import(params[:file])
redirect_to root_url, notice: "Contacts imported."
end
# the following code taken from RailsCast 396, may be useful
# def index
# @products = Product.order(:name)
# respond_to do |format|
# format.html
# format.csv { send_data @products.to_csv }
# format.xls # { send_data @products.to_csv(col_sep: "\t") }
# end
# end
# GET /contacts
# GET /contacts.json
def index
@contacts = Contact.all
end
# GET /contacts/1
# GET /contacts/1.json
def show
end
# GET /contacts/new
def new
@contact = Contact.new
end
# GET /contacts/1/edit
def edit
end
# POST /contacts
# POST /contacts.json
def create
@contact = Contact.new(contact_params)
respond_to do |format|
if @contact.save
format.html { redirect_to @contact, notice: 'Contact was successfully created.' }
format.json { render :show, status: :created, location: @contact }
else
format.html { render :new }
format.json { render json: @contact.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /contacts/1
# PATCH/PUT /contacts/1.json
def update
respond_to do |format|
if @contact.update(contact_params)
format.html { redirect_to @contact, notice: 'Contact was successfully updated.' }
format.json { render :show, status: :ok, location: @contact }
else
format.html { render :edit }
format.json { render json: @contact.errors, status: :unprocessable_entity }
end
end
end
# DELETE /contacts/1
# DELETE /contacts/1.json
def destroy
@contact.destroy
respond_to do |format|
format.html { redirect_to contacts_url, notice: 'Contact was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_contact
@contact = Contact.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def contact_params
params.require(:contact).permit(:first_name, :last_name, :email_address)
end
end
这是我的routes.rb
文件:
Rails.application.routes.draw do
# generated by scaffold
# resources :contacts
# taken from railscast 396
resources :contacts do
collection { post :import }
end
# You can have the root of your site routed with "root"
root 'contacts#index'
end
更新:
这是我的index.html.erb视图:
<p id="notice"><%= notice %></p>
<h1>Listing Contacts</h1>
<table>
<thead>
<tr>
<th>First name</th>
<th>Last name</th>
<th>Email address</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @contacts.each do |contact| %>
<tr>
<td><%= contact.first_name %></td>
<td><%= contact.last_name %></td>
<td><%= contact.email_address %></td>
<td><%= link_to 'Show', contact %></td>
<td><%= link_to 'Edit', edit_contact_path(contact) %></td>
<td><%= link_to 'Destroy', contact, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Contact', new_contact_path %>
<h2>Import Contacts</h2>
<%= form_tag import_contacts_path, multipart: true do %>
<%= file_field_tag :file %>
<%= submit_tag "Import" %>
<% end %>
答案 0 :(得分:3)
应该是 CSV
而不是Csv
。
when ".csv" then CSV.new(file.path, nil, :ignore)
<强> 更新 强>
好像你正在使用导航播放中所述的roo
gem。如果符合this链接,则代码应如下所示 Rails 4
when ".csv" then Roo::CSV.new(file.path, nil, :ignore)
when ".xls" then Roo::Excel.new(file.path, nil, :ignore)
when ".xlsx" then Roo::Excelx.new(file.path, nil, :ignore)