uninitialized constant Contact :: Csv

时间:2015-08-22 17:01:57

标签: ruby-on-rails csv ruby-on-rails-4

注意:在我的application.rb文件中,我同时需要csviconv

我正在构建一个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 %>

1 个答案:

答案 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)